一、多进程并发
在多任务系统中,每个进程的正确执行不仅依赖与用户地址空间的内容,还依赖于寄存器和内核地址空间的内容。在内核空间中为每一个进程维护了一个 task_struct 对象,其中保存了调度该进程所需的所有信息。调度器根据不同的调度策略决定进程执行停止(抢占)和下一个应该执行的线程。进程切换过程首先会保存当前进程的上下文(寄存器,缓存,内核栈,用户栈等),然后切换地址空间映射(切换页表),载入新进程上下文。
![b4568018e851902609f4e1c43fd1b5b4.png](https://i-blog.csdnimg.cn/blog_migrate/56eea47b3304e8c79593a656267e8ca6.png)
多进程调度可以实现并行或并发的功能。但是由于不同进程拥有各自的虚拟地址空间,进程切换和通信的开销比较大。
二、多线程并发
单线程进程只有一个主线程入口点,函数帧以此为起点展开。事实上完全可以在进程地址空间创建多个线程入口点,每个线程拥有独立的栈区间。线程是在堆区动态创建的栈空间,而 fork 进程则是完整拷贝当前进程的内容到新开辟的内存空间,所以线程的创建开销远小于进程。另外,操作系统以线程为调度的基本单位,线程之间的切换只需要切换上下文,不需要切换虚拟内存空间和缓存,调度开销大大减少。
![d0e0baa03b14f02d94b8ebb39a035505.png](https://i-blog.csdnimg.cn/blog_migrate/f0f08da69843a5cc86ab82468b39ac83.jpeg)
三、<thread> 库
std::thread 类型内保存了一个 std::thread::id 类型的成员变量,thread::id 类型内又保存了一个 pthread_t 类型的成员变量。可见,<thread> 库是对 C POSIX thread 库的一个封装。
1. 创建进程
#include
2. 线程与std::thread对象的关系
join() 与 detach()
默认情况下,当创建线程的 std::thread 对象被销毁时,如果该对象是 joinable (即std::thread 对象保存了正在运行的线程实例)则会调用 std::terminate() 终止进程。所以,应该在对象被销毁之前调用 join() 或 detach()。
其中,join() 会保证线程在执行完之前,调用线程处于阻塞状态,同时会释放 id 成员变量(joinable() 返回 false)。这就相当于调用线程在 join()处停止,等新线程执行完后再执行调用线程 join() 后面的命令。
detach() 保证了新线程在 std::thread 对象销毁后继续执行,同样会释放 id 成员变量。
转移底层线程对象所有权
std::thread 对象不可拷贝但可转移。
void
这样就可以把 std::thread 对象作为函数的型参和返回值。
void
3. 获取其他信息
硬件支持线程数目
硬件真正能够并行执行的线程数目是有限的,所以单从性能考虑,完全不必增加比这更多的线程。
unsigned
std::thread::id 成员变量
std
std::thread::id 类内部重载了各种比较函数(可以将其作为关联容器的 key)和 <<用于标准输出。
常见的多线程编程模型
1. Boss/Worker Model
由一个主线程(Boss 线程)循环相应异步请求,根据请求类型创建对应的 Worker 线程处理该请求。Worker 线程可以将处理结果发送给需求方,也可以将处理结果同步给 Boss 线程。Boss 承接业务,分配工作,Worker 干具体工作。
![38ca59cdc809f1107e3774813ebd4c76.png](https://i-blog.csdnimg.cn/blog_migrate/36da38d3e11000999ad8af4377c5c444.png)
2. Peer Model
对于一个有固定输入的CPU密集型任务,可以将其划分成几个更小的任务由多个线程完成,可以极大的提升效率。
![78cf18327e97269ae37bceda36927acb.png](https://i-blog.csdnimg.cn/blog_migrate/d7ddfe39bdd291e3029ba77e082836d4.png)
3. Pipeline Model
如果数据处理可以划分成若干个阶段,则可以为每个阶段创建一个线程。每个阶段线程从前一个阶段线程接收输入,做一些工作,然后将结果输出给下一个线程。这样虽然处理每一个输入事件的总时间略有增加(考虑到线程切换),但是相同时间内处理的事件数目增加了,也可以提升效率。
![dad9b04584273ca20708b9f878f5c4a6.png](https://i-blog.csdnimg.cn/blog_migrate/aea379ac85dbf63978c49980f7054e25.png)
链接
[1] Linux 线程切换和进程切换的方法
第25课 std::thread对象的析构