Week5 同步机制
声明:本文的图片和内容均来自Coursera课堂。
1. 进程的并发执行
并发的特点:进程的执行是间断性的;进程的相对执行速度是不可预测的;在并发执行的情况下,共享资源的使用会带来一些制约。
举例来说,有两台ATM机,两个人分别用同一个账号进行取款,相当于两个进程。该账户余额为5000元,那么在取款前ATM机就会几乎同时读取系统内的余额数字,即两台ATM机都读入了5000元并显示给用户看。然后1号ATM取钱1000,2号ATM取钱2000,可是由于两台ATM之前读取的余额是5000,所以操作完成后,存入数据库的余额数值就会是4000(如果ATM1先完成操作)或3000(如果ATM2先完成操作。无论是哪种情况,这明显与事实不符合,这就是并发进程会产生的问题之一。
从上述案例可知,有些进程之间,其实是有先后顺序要求的,再比如提取数据、复制数据、显示数据、写入数据四个进程,由于进程的并发性,如果显示数据先执行,则可能会显示一个错误的数据(提取数据还未执行完毕)。通常来说,提取数据是一定要先执行完毕才可以执行后续步骤,而复制数据和显示数据其实可以同时执行。同一轮的复制数据和显示数据执行完毕后,才可以执行写入数据。因此进程之间的制约关系就很明显了。
2.进程互斥
2.1 基本概念
竞争条件
两个或多个进程读写某些共享数据区域时,而最后的操作结果取决于进程运行的精确时序,也就是谁先谁后会导致不同的结果。这种情况就叫做竞争条件。
进程互斥(Mutual Exclusive)
由于各进程要求使用共享资源(变量、文件等),而这些资源需要排他性使用(非我莫属),各进程之间竞争使用这些资源的情况,就叫做进程互斥。
临界资源(critical resource)
系统中某些资源一次只允许一个进程使用,这样的资源称为临界资源或共享变量或互斥资源。
临界区或互斥区(critical section)
各个进程中对某个临界资源(共享变量)实施操作的程序片段。
临界区(互斥区)的使用原则:
- 没有进程在临界区时,想进入临界区的进程可进入;
- 不允许两个进程同时处于其临界区中;
- 在临界区外运行的进程不得阻塞其他进程进入临界区;
- 不得使进程无限期等待进入临界区;
2.2 进程互斥的软件解决办法
软件方案:Dekker解法、Peterson解法
1).用一个free标志,标识临界区是否为空闲,true标识有,false标识没有。初值为false。但是这种简单的思路仍会有以下问题:即P进程执行到while判断后还没改变free标识就退出cpu了(因为一条看似简单的语句其实在机器语言里是分很多步执行的),而此时Q进程进来执行到临界区。这样临界区就有两个进程在执行了。所以,要将while(free)和free=true合并为一句原语。
2).Dekker算法
用一个turn标识,来表示限制轮到哪个进程进入临界区。然后使用如下图代码进行循环判断:
具体可以参见博客:https://blog.csdn.net/wsw875421872/article/details/17222219,博主解释的挺清楚的。
3).Peterson算法
该算法解决了互斥访问的问题,而且克服了强制轮流法的缺点,可以完全正常地工作。两个进程互斥的时候可以解决,但是多个进程互斥的时候呢?
同样提供一个供参考的博文:https://blog.csdn.net/JustJavaC2016/article/details/78660768
2.3 进程互斥的硬件解决方案
1).中断屏蔽
在进程进入临界区时,用原语实现“关中断”指令;进程从临界区出来时,用原语实现“开中断指令”
特点:
- 简单、高效;
- 但是代价高,限制CPU并发能力;
- 不使用于多处理器;
- 适用于操作系统本身,不适用于用户进程(无特权指令)。
2).测试并加锁指令(TSL(XCHG)指令)
能不能用于多处理器?
3).交换指令
忙等待(busy waiting)
忙等待定义:进程在得到临界区访问权前,持续测试而不做其他事情。
忙等待对于单处理器,是很不好的。但是在多处理器中,是可行且不错的解法。这种在一个处理器上循环判断,在另一个处理器上等待进入临界区的方式,叫自旋锁(spin lock)
建议参考博文:https://blog.csdn.net/daaikuaichuan/article/details/82950711
3.进程同步
进程同步(synchronization):指系统中多个进程中发生的事件存在某种时序关系,需要互相合作,共同完成一项任务。即一个进程到达某个点时,需要等待另一个进程发送相应信号,才能继续接下来的步骤。
案例: 生产者/消费者问题,也称为有界缓冲区问题。
问题描述:
- 一个或多个生产者生产某种类型的数据放置在缓冲区中;
- 有消费者从缓冲区中取数据,每次取一项;
- 只能有一个生产者或消费者对缓冲区进行操作;
要解决的问题: - 当缓冲区已满时,生产者不会继续向其中添加数据;
- 当缓冲区为空时,消费者不会从中取走数据
避免忙等待:睡眠与唤醒操作(原语),下图的代码可有助于理解上述问题
其他案例
下图左边,P1进程执行完后,才能开启P2,P3,P6进程,这三个进程可并行执行。其中P3执行完后,才可以进行进程P4,P5。直到P2,P4,P5,P6执行完后,才可以执行P7,P8进程。可以看到,每个进程之间的执行顺序都有所配合和约束,这就是进程之间的同步关系。下图右边也类似。
4.信号量及P、V操作
这是一种特殊的同步机制,既能解决同步问题,又能解决互斥问题(可以看作一种特殊的同步)。
4.1 信号量
信号量是一个特殊的变量,用于进程间传递信息的一个整数值。对信号量只能实施三种操作:初始化,P和V
4.2 PV操作
P、V操作为原语操作。
在信号量上定义了三个操作:初始化(非负)、P操作、V操作。
最初提出的是二元信号量(解决互斥),之后推广到一般信号量或计数信号量(解决同步)。
4.3 PV操作解决进程间互斥问题
- 分析并发进程的关键活动,划定临界区
- 设置信号量mutex(mutual exclusive),初值为1
- 在临界区前实施P(mutex)操作
- 在临界区之后实施V(mutex)操作
5. 案例分析
5.1 生产者/消费者问题
同一个信号量,分布在两个代码段中,这就是两个代码段之间的同步关系。
注意,红蓝的两条P语句可以互换吗?
不行,会产生死锁问题。
两条V语句可以互换位置吗?
理论上来说不会出问题,但是会稍微延长临界区的无用大小,降低程序算法。
5.2 第一类读者/写者问题——读者优先
1)问题描述:
多个进程共享一个数据区,这些进程分为两组:
- 读者进程:只读取数据区中的数据
- 写者进程:只往数据区写数据
2)要求条件:
- 允许多个读者同时执行读操作
- 不允许多个写者同时操作
- 不允许读者、写者同时操作
3)问题分析:
如果读者执行:
- 无其他读者、写者,该读者可读;
- 若已有写者等,但有其他读者正在读,则该读者也可以读;
- 若有写者在写,该读者必须等;
如果写者执行:
- 无其他读者、写者,该写者可以写;
- 若有读者正在读,该写者等待;
- 若有其他写者正在写,该写者等待
即写者与其他写者、读者都互斥。
4)问题解法:
因为不是所有读者进程都要进行PV操作的,因为多个读者可以共同读。所以,其实只要第一个读者进行P操作,最后一个读者进行V操作即可。
而在引入rc计数器之后,rc这个变量空间就变成了多个读者进程的共享变量,因此要进行临界区的设定,保证rc变量的操作不冲突。
6.本章重点
- 基本概念
- 竞争条件、临界区
- 进程同步、进程互斥
- 自旋锁、忙等待
- 信号量、PV操作
- 经典问题模型及解决方案
- 生产者-消费者问题
- 读写者问题
- 重要名词:竞争条件、忙等待、临界资源、临界区、进程互斥、进程同步、信号量、PV操作、锁、自旋锁、生产者消费者问题、读写者问题