《操作系统》课程笔记(Ch04-多线程编程)
基本概念
多线程进程与多线程服务器示意图
并行与并发
-
并行系统:同时执行多个任务
-
并发系统:支持多个任务,允许所有任务都能取得进展
没有并行,并发也是可能的
Amdahl定律
并行化加速比:speedup;N:任务数;S:串行比例
\(speedup \leq \frac{1}{S+\frac{1-S}{N}}\)
当N趋于无穷大时,加速比收敛到\(1/S\)。
并行的两种类型
并行应用程序通常混合使用这两种策略。
- 数据并行
- 任务并行
多线程模型
用户线程和内核线程
- 用户线程:暴露给用户,工作在用户层
- 内核线程:工作在内核层,操作系统管理
多线程模型在这两种线程之间建立联系。
多对一模型
多个用户线程映射到一个内核线程,任一时间只有一个线程可以访问内核。显然这种实现不能用于多核系统。
一对一模型
一个用户线程映射到一个内核线程。提供了比多对一模型更好的并发功能。缺点是创建内核线程的开销影响性能。
多对多模型
多个用户线程映射到多个内核线程(≤用户线程)。允许创建多个用户线程,且相应内核进程能支持多处理器系统。某个线程阻塞时,内核可以调度另一个线程执行。
双层模型
多对多的变种,融合了多对多模型与一对一模型。
* 线程库
操作系统提供给程序员的创建和管理线程的API。
-
Pthreads
使用
pthread_join()
等待线程结束 -
Windows线程
-
Java
* 隐式多线程
将多线程的创建和管理交给编译器和运行时库完成。
线程池
在进程开始时创建一定数量的进程,加到线程池中等待工作。当服务器收到请求时,唤醒池中的一个线程(如果有可用的),并完成服务,然后线程归还到池中再等待工作。
优点:不需要反复创建线程;限制了可用进程的数量;更灵活的任务执行机制
OpenMP
提供了一组编译指令和API。
大中央调度GCD
一组扩展,允许程序员将某些代码区段并行运行。
多线程的问题
fork与exec的语义
程序的某个线程调用了fork,新进程要不要复制所有线程,还是仅复制该调用线程?
通常策略:如果fork后立即exec,则不用复制所有线程,因为exec的程序会替换整个进程;否则复制所有线程比较合适。
信号处理
UNIX信号:用于通知进程某个特定事件已经发生。
多线程下的信号应该被传递到哪里?
- 信号所适用的线程
- 所有线程
- 某些线程
- 一个特定线程统一处理所有信号
线程撤销
指在线程完成之前终止线程。
- 异步撤销:一个线程立即终止目标线程
- 延迟撤销:目标线程不断检查它是否应终止
线程本地存储
每个线程可能需要存储自己的某些数据(TLS)。与局部变量不同,局部变量只在单个函数调用时可见,TLS数据在多个函数调用时都可见。
调度程序激活
操作系统在实现多对多或双层模型时候,在用户和内核线程之间增加一个中间数据结构:轻量级进程LWP。