程序员的自我修养(二)线程基础
线程
线程(又称轻量级进程)是程序执行流的最小单元。
一个标准的线程由线程id、当前指令指针、寄存器集合和堆栈组成。
一个进程由一个或多个线程组成,各线程之间共享程序的内存空间(包括代码段、数据段、堆等)及一些进程级资源(如打开文件和信号)。
- 多线程可以互不干扰地并发地执行,并共享进程的全局变量和堆的数据。
线程私有 | 进程所有(线程之间共享) |
---|---|
局部变量、函数的参数、TLS数据 | 全局变量、堆上的数据、函数里的静态变量、程序代码、打开的文件 |
线程调度
线程通常拥有至少三种状态:
- 运行:线程正在执行
- 就绪:线程可以立刻执行,但CPU已经被占用
- 等待:线程正在等待某一事件发生,无法执行。
线程调度算法:
- 优先级调度
- 轮转法
可抢占线程和不可抢占线程
Windows和Linux
Windows线程
CreateProcess
CreateThread
Linux任务
Linux将所有的执行实体都称为任务,每个任务概念上都类似于一个单线程的进程,具有内存空间、执行实体、文件资源等。
Linux下,不同的任务之间可以选择共内存空间–>共享了同一个内存空间的多个任务构成了一个“进程”,这些任务也就成了这个“进程”里的线程
fork : 复制当前进程
exec : 使用新的可执行映像覆盖当前可执行映像
clone : 创建子进程并从指定位置开始执行
写时复制
写时复制指的是,两个任务可以同时*地读取内存,但任意一个任务试图对内存进行修改时,内存会复制一份提供给修改方单独使用,以免影响到其他的任务使用。
线程安全
竞争与原子操作
WindowsAPI原子操作相关函数:
InterlockedExchange:原子地交换两个值
InterlockedDecrement:原子地减少一个值
InterlockedIncrement:原子地增加一个值
InterlockedXor:原子地进行异或操作
同步和锁
- 信号量
- 互斥量
- 临界区
- 读写锁
- 条件变量
可重入与线程安全
一个函数被重写入,表示这个函数没有执行完成,由于外部因素或内部调用,又一次进入该函数执行。
一个函数要被重写入,可能的原因有:
- 多个线程同时执行这个函数
- 函数自身调用自身
一个函数被称为可重写入的,表明该函数被重写入之后不会产生任何不良后果。
可重入函数的特点:
- 不使用任何(局部)静态或全局的非const变量
- 不返回任何(局部)静态或全局的非const变量的指针
- 仅依赖于调用方提供的参数
- 不依赖任何单个资源的锁
- 不调用任何不可重入的函数
线程模型
- 一对一模型
- 多对一模型
- 多对多模型