操作系统: 进程间通信
参考资料: 《现代操作系统 3th edtion》原书第二章 进程与线程
在 xmind 上记录
一、临界区
对共享内存进行访问的程序片段称作临界区域(critical region)或临界区(criticalsection)
使并发进程正常协作的条件
- 任何两个进程不能同时处于其临界区
- 不应对CPU的速度和数量做任何假设
- 临界区外运行的进程不得阻塞其他进程
- 不得使进程无限期等待进入临界区
二、忙等待的互斥
评价: 浪费了CPU时间,而且还可能引起预想不到的结果
屏蔽中断(不好)
- 把屏蔽中断的权力交给用户进程是不明智的
- 屏蔽中断对于操作系统本身而言是一项很有用的技术,但对于用户进程则不是一种合适的通用互斥机制
- 对多核CPU无效
锁变量(无法解决问题)
- 有可能出现A发现没有加锁准备进入临界区,在A加锁之前B也发现了并先于A加锁,导致两者同时进入临界区
- 或者: 第二个进程恰好在第一个进程完成第二次检查之后修改了锁变量的值
严格轮换法
- 连续测试一个变量直到某个值出现为止,称为忙等待(busy waiting)
- 只有在有理由认为等待时间是非常短的情形下,才使用忙等待。用于忙等待的锁,称为自旋锁(spinlock)
- 尽管该算法的确避免了所有的竞争条件,但由于它违反了条件3,所以不能作为一个很好的备选方案
Peterson解法
TSL指令
- 硬件支持的方案
- 执行TSL指令的CPU将锁住内存总线,以禁止其他CPU在本指令结束之前访问内存
三、睡眠与唤醒
-
sleep是一个将引起调用进程阻塞的系统调用,即被挂起,直到另外一个进程将其唤醒
-
wakeup调用有一个参数,即要被唤醒的进程
四、信号量
Dijkstra建议设立两种操作:down和up(分别为一般化后的sleep和wakeup)
- 对一信号量执行down操作(P操作),则是检查其值是否大于0。若该值大于0,则将其值减1(即用掉一个保存的唤醒信号)并继续;若该值为0,则进程将睡眠,而且此时down操作并未结束
- up操作(V操作)对信号量的值增1。如果一个或多个进程在该信号量上睡眠,无法完成一个先前的down操作,则由系统选择其中的一个(如随机挑选)并允许该进程完成它的down操作
- 如果每个进程在进入临界区前都执行一个down操作,并在刚刚退出时执行一个up操作,就能够实现互斥
信号量的另一种用途是用于实现同步(synchronization)
五、互斥量
信号量的一个简化版本,不需要计数能力
可以处于两态之一:解锁和加锁
-
当一个线程(或进程)需要访问临界区时,它调用mutex_lock
- 如果该互斥量当前是解锁的(即临界区可用),此调用成功,调用线程可以*进入该临界区
- 另一方面,如果该互斥量已经加锁,调用线程被阻塞,直到在临界区中的线程完成并调用mutex_unlock
- 如果多个线程被阻塞在该互斥量上,将随机选择一个线程并允许它获得锁
-
离开临界区调用mutex_unlock解锁
检查数值、修改变量值以及可能发生的睡眠操作均作为一个单一的、不可分割的原子操作完成
XMind: ZEN - Trial Version