同步
多道程序设计:现代操作系统的重要特性
并行
进程和线程:操作系统抽象出来用于支持多道程序设计
CPU调度:实现多道程序规则
调度算法:不同的策略
- 独立的线程
不和其他线程共享资源或者状态
确定性:输入决定状态
可重现:能够重现起始条件
调度顺序不重要
- 合作线程
在多个线程中共享状态
不确定性
不可重现
- 不确定性和不可重现意味着bug可能是间歇性发生的
为什么要合作
- 进程和线程,计算机和设备需要合作
- 优点1:共享资源
- 优点2:加速
- 优点3:模块化
程序可以调用fork()函数来创建一个新的进程
假设两个进程并发执行
Race Condition (竞态条件)
系统缺陷:结果依赖于并发执行或者事件的顺序/时间
- 不确定性和不可重现
如何避免竞态?
- 让指令不会被打断
Atomic Operation(原子操作)
- 原子操作是指一次不存在任何中断或者失败的执行
该执行成功结束
或者根本没有执行
并且不应该发现任何部分执行的状态
- 实际上的操作往往不是原子的
有些看上去是原子操作,实际上不是
连X++这样的简单语句,实际上都是由3条指令构成
有时候甚至连单挑指令都不是原子的
Critical Section(临界区)
临界区是指进程中的一段需要访问共享资源并且当另一个进程处于相应的代码区域时不会被执行的代码区域
- 互斥:同一时间临界区最多存在一个线程
- Progress:如果一个进程、线程想要进入临界区,那么它最终会成功
- 有限等待:如果一个线程i处于入口区,那么在i的请求被接受之前,其他线程进入临界区的时间是有限制的
- 无忙等待:如果一个进程在等待进入临界区,那么在它可以进入之前会被挂起
临界区对代码的保护:
- 禁用硬件中断:
没有中断,没有上下文切换,没有并发
硬件将中断处理延迟到中断被启用之后
大多数现代计算机体系结构都是提供指令来完成
进入临界区
禁用中断
离开临界区
启用中断
一旦中断被禁用,线程就无法被停止
要是临界区可以任意长怎么办?
一定要慎用
基于软件的解决方案
- 更高级的抽象
硬件提供了一些原语:中断禁用,原子指令等
操作系统提供更高级的编程抽象来简化并行编程:锁,信号量等
锁是一个抽象数据结构
使用锁来编写临界区
大多数现代计算机体系结构都提供了特殊的原子操作指令
test-and-set测试和位置
交换:交换内存中的两个值
Mutual exclusion(互斥)
当一个进程处于临界区并访问共享资源时,没有其他进程会处于临界区并且访问任何相同的共享资源
Dead Lock(死锁)
两个或者以上的进程,在相互等待完成特定的任务,而最终没办法将自身的任务进行下去
Starvation(饥饿)
一个可执行的进程被调度器持续忽略,以至于隋斐然处于可执行状态但是却不被执行