C++服务端面试准备(4)Linux及多线程相关

声明:本文内容纯属博主本身查找和概括的我的所需的知识点,仅做参考,若有错误,博主强烈但愿您指出。若是您是某个知识点的原创博主,若有须要,可联系本人加上连接。本文内容会根据博主所需进行更新,但愿你们多多关照。

文件IO相关知识点

  • 七种文件类型:普通文件(-)、目录(d)、符号连接(l)、管道(p)、套接字(s)、字符设备(c)、块设备(b)
  • shell中文件的颜色:白色——普通文件、绿色——可执行文件、红色——压缩文件、蓝色——目录、青色——连接文件、黄色——块设备字符设备管道、灰色——其余文件
  • PCB:进程控制块,存放文件描述符表,本质是一个结构体
  • PCB内部成员:进程ID、进程状态、当前工做目录、文件描述符表、用户ID组ID、信号相关的信息等
  • 一个进程有一个文件描述符表,大小为1024字节,前三个被占用,分别是STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO
  • 文件描述符做用:寻找磁盘文件
  • 查看磁盘命令:df -h

并发与并行

  • 并发:

       是指同一个时间段内多个任务同时都在执行,而且都没有执行结束。并发任务强调在一个时间段内同时执行,而一个时间段由多个单位时间累积而成,因此说并发的多个任务在单位时间内不必定同时在执行 。linux

  • 并行:

       是说在单位时间内多个任务同时在执行。c++

       在多线程编程实践中,线程的个数每每多于CPU的个数,因此通常都称多线程并发编程而不是多线程并行编程。shell

进程相关知识点

  • 查看进程:ps auxps ajx能显示父进程,查看内存占用:free -h,查看当前cpu:top
  • MMU:虚拟内存映射单元,单位为4k,虚拟内存经过MMU映射到物理内存
  • 寄存器4字节,1字节8位
  • 进程基本状态:初始态、就绪态、运行态、挂起态、终止态

       运行态->挂起态:等待使用资源,如等待外设传输、人工干预等
       运行态->就绪态:出现有更高优先权进程数据库

  • 父子进程共享:文件描述符、mmap映射区、全局变量读时共享、写时复制
  • 孤儿进程:父进程先于子进程结束,子进程称为孤儿进程,init进程变为它的父进程并接管孤儿进程
  • 僵尸进程:当子进程比父进程先结束,而父进程又没有回收子进程,子进程的进程描述符仍然保存在系统中,此时子进程将成为一个僵尸进程

进程间通讯相关知识点

  • 进程间经常使用的4种通讯方式:管道(使用简单)、信号(开销小)、共享映射区(无血缘关系可用)、本地套接字(稳定)
  • 管道:

       本质为一个伪文件,内核使用环形队列机制,借助内核缓冲区(4k)实现,数据一旦读走,管道中不在存在编程

  • 共享映射区:

       mmap,一种内存映射文件的方法,将一个文件或者其它对象映射进内存,无血缘关系的进程间可以使用共享映射区进行通讯,在要求高性能的应用中比较经常使用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap,mmap的实现和硬件有关windows

  • 信号:

       简单但不能携带大量信息,知足条件才发送,至关于中断,有很强的延时性,全部信号都由内核(PCB)发送和处理
       信号4要素:编号、名称、事件、默认处理动做
       信号处理方式:执行默认动做(终止进程、忽略信号、终止进程并生成CORE文件、暂停进程、继续运行进程)、忽略、捕捉安全

  • 查看信号列表:kill -l

建立会话要注意什么

  • 建立会话的进程不能是进程组组长,不然出错返回
  • 该进程变成新会话的首进程和一个新进程组组长
  • 须要有root权限(Ubuntu不须要)
  • 新会话丢弃原有的控制终端,该会话没有控制终端
  • 建立会话时,先调用fork,父进程终止,子进程再调用setsid()

建立守护进程

  1. 在父进程中执行fork并exit退出;
  2. 在子进程中调用setsid函数建立新的会话;
  3. 在子进程中调用chdir函数,让根目录 "/" 成为子进程的工做目录;
  4. 在子进程中调用umask函数,设置进程的umask为0;
  5. 在子进程中关闭任何不须要的文件描述符(close(fd))或者重定向"/dev/null"

线程相关知识点

  • 查看全部线程:top -Hps -Lf 进程号,查看该进程的线程
  • 线程定义:LWP,轻量级进程,有独立的PCB和共享地址空间
  • 为何会出现线程安全:当一个线程在操做共享资源时,未执行完毕的状况下,其余线程参与进来,致使共享资源出现安全问题。
  • 保护共享数据区方法:互斥量、读写锁、条件变量、信号量(C语言)、原子操做(一般用来保护单个变量)、windows临界区
  • 死锁:对一个锁反复Lock,或者2个线程各自锁上一把锁后请求对方的锁
  • 死锁解决方法:按一样的顺序上锁,c++11用std::lock(mutex1, mutex2, ...)

条件变量的使用

  1. 建立一个互斥量,用lock_guard或者unique_lock封装互斥量
  2. 建立条件变量,用wait成员函数等待条件知足
  3. 另外一线程使用notify_one或notify_all后激活wait
  4. wait拿锁后判断第二个参数是否为true,若是true则执行下面的代码,若是false则表示条件不知足,继续等待下次的激活

sleep()和wait()的区别

  • sleep()包含<windows.h>头文件,wait()包含<wait.h>文件
  • sleep()占着CPU休眠,不会解锁,wait()释放锁并腾出CPU资源等待唤醒并拿锁

进程与线程的区别

  1. 进程是分配资源的基本单位;线程是系统调度和分派的基本单位。
  2. 一个进程能够拥有多个线程,属于同一进程的线程,具备相同的地址空间,堆是共享的,栈是私有的。
  3. 进程开销大,线程开销小
  4. 线程间通讯相对方便,进程间通讯相对复杂
  5. 多进程更健壮,多线程容易出错
  6. 进程是一个资源的容器,为进程里的全部线程提供共享资源,是对程序的一种静态描述,线程是计算机最小的调度和运行单位,是对程序的一种动态描述

为何使用多线程

  1. 避免阻塞

       单个线程中的程序,是顺序执行的。若是前面的操做发生了阻塞,那么就会影响到后面的操做。这时候能够采用多线程多线程

  1. 避免CPU空转

       有时候处理一条请求,会涉及到数据库访问、磁盘IO等操做,这些操做的速度比CPU慢不少,而在等待这些响应的时候,CPU却不能去处理新的请求,没有充分利用资源,这时多线程就发挥做用了并发

  1. 提高性能

       在知足条件的前提下,多线程确实能提高性能:
       第1,任务具备并发性,子任务之间不能有前后顺序的依赖,必须是容许并行的,另外,还不能有资源竞争
       第2,只有在CPU是性能瓶颈的状况下,多线程才能实现提高性能的目的。
       第3,就是须要有多核CPU才行,若是上述条件都知足,有一个经验公式能够计算性能提高的比例,叫阿姆达尔定律:
       速度提高比例 = 1/[(1-P)+(P/N)]
       其中P是可并行任务的比例,N是CPU核心数量app

gdb基础调试

编译:gcc加要加-g,-g保留函数名和变量名
启动:gdb 可执行文件
传参:set args 参数1 参数2 ...

操做 命令
查看第n行的上下程序 l n
设置查看n行上下程序 set listsize n
查看其余文件程序 l 文件名 : n 或 函数名
在n行打断点 b n
查看断点 i b
删除断点 d n,n为断点编号
设置无效或有效断点 dis / enb n,n为断点编号
条件断点 b n if 变量==值
运行 r 或 start,r直接到断点,start进入程序第一行
单步执行 n
执行到下一个断点 c
查看变量信息 p 变量名
查看变量类型 ptype 变量名
一直显示变量信息 display 变量名
取消显示变量 先i display 查看变量编号n,而后undisplay n
进入函数 s
离开函数 finish
跳出循环 until,须要删除断点
离开gdb q

gdb也能够直接调试core文件查看错误:

1.当一个程序出现段错误时,会出现如下提示:
       Segmentation fault (core dumped)
       core 指该程序运行时,进程空间的内存分布
       dumped 表示内核已经把core抛出
       一般,出现段错误提示时程序运行目录下应该自动生成一个core文件用来存储内核抛出的core,可是,因为linux环境通常默认设置core文件限制为0,因此通常状况下没法生成core文件。

2.查看core文件大小限制:ulimit -c

3.将其修改成无限制:ulimit -c unlimited

4.运行命令:gdb 执行文件名 core

5.gdb输入  where

gdb多线程调试

命令行查看线程信息:

  • 查看当前运行的进程:ps aux|grep 执行文件名
  • 查看当前运行的轻量级进程:ps -aL|grep 执行文件名
  • 查看主线程和新线程的关系:pstree -p 主线程id

线程栈结构的查看:

  • 获取线程ID
  • 经过命令查看栈结构:ps stack 线程ID

利用gdb查看线程信息:

  • 将运行着的进程附加到gdb调试器当中,查看是否建立了新线程:gdb attach 主线程ID

进入gdb调试:

  • info inferiors:查看当前进程
  • info threads:查看当前线程
  • bt:查看当前线程栈结构
  • thread n/ID:切换线程(n表明第几个线程)
  • break 行号/函数名:设置当前线程断点
  • break file.c:100 thread all:在file.c文件第100行处为全部通过这里的线程设置断点。
  • set scheduler-locking off/on/step
    在使用step或者continue命令调试当前被调试线程的时候:
    off:不锁定任何线程,也就是全部线程都执行,这是默认值。
    on:只有当前被调试程序会执行。
    step:在单步的时候,除了next过一个函数的状况之外(熟悉状况的人可能知道,这实际上是一个设置断点而后continue的行为),只有当前线程会执行。
  • thread apply ID1 ID2 command:让一个或者多个线程执行GDB命令command
  • thread apply all command:让全部被调试线程执行GDB命令command

makefile基础

  • 向下检索内容,根据时间判断哪一个文件须要更新
  • 目标:依赖
           命令
  • 查找目录下指定文件类型:变量 = $(wildcard 文件路径)
  • 匹配替换:变量 = $(patsubst 原名称, 替换后的名称, 源文件)
  • notdir:去除文件名的目录函数
  • basename:取文件名函数
  • $@:规则中的目标 $<:规则中的第一个依赖 $^:规则中全部依赖
  • /:换行
  • 自定义命令:
    名称:
           命令
  • 声明伪目标:
    .PHONY:名称

随便说一下Linux和Windows的区别

  1. 兼容性:windows向后兼容,linux内核升级可能就不兼容,软件方面windows占优
  2. 进程:单个进程windows不能执行,linux能够
  3. 性能:windows图形界面,不少渲染,性能下降,linux少,用命令行工做,性能好
  4. 文件系统:linux有多种文件系统,对文件和设备的管理占优,windows较差
  5. 中断优先级:windows有32级,linux彷佛只有5级,异常分为故障(fault)、陷阱(trap)和停止(abort)
  6. 软件启动:windows用注册表,linux用配置文件,灵活性高
相关文章
相关标签/搜索