一、什么是进程同步?
二、什么是进程互斥?
临界资源:一个时间段内只允许一个进程使用的资源
为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则:
- 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;
- 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待;
- 有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿);
- 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
注意:
5. 进程同步也可以说是进程之间的直接制约(合作)关系:因为进程之间是有直接的合作的,需要进程之间进行相互配合,各进程的工作推进需要遵循一定的先后顺序
6. 进程互斥也可以说是进程之间的互斥制约(合作)关系:因为进程之间并没有直接的合作关系,他们之间只是想要互斥的使用某种系统的临界资源,所以才会产生这种制约关系
三、信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。
- 信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。
- 原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。软件解决方案的主要问题是由“进入区的各种操作无法一气呵成”,因此如果能把进入区、退出区的操作都用“原语”实现,使这些操作能“一气呵成”就能避免问题。
- 一对原语:wait(S)原语和signal(S)原语,可以把原语理解为我们自己写的函数,函数名分别为wait和signal,括号里的信号量s其实就是函数调用时传入的一个参数。
wait、signal原语常简称为P、V操作(来自荷兰语proberen和verhogen)。因此,做题的时候常把wait(S)、signal(S)两个操作分别写为P(S)、V(S)
1)整型信号量
2)记录型信号量
进入wait原语时:
S.value 先进行了-1操作,如果S.value的值在经过-1操作之后 < 0,则说明原本的S.value的值是<=0的,而S.value的数值其实就代表着资源的数量,所以资源的数量是 <= 0, 则需要使用block原语来使该进程由运行态进入阻塞态,并挂到信号量S的等待(阻塞)队列中。
进入signal原语时:
S.value 先进行了+1操作,如果S.value的值在经过+1操作之后 <= 0,则说明原本的S.value的值是<= -1的,而此时的S.value的数值的绝对值可以理解为等待队列中的进程数量,所以等待队列中的进程数量是 >= 1的, 则需要使用wakeup原语来唤醒等待队列中的一个进程(即位于队头的进程),让该进程从阻塞态变为就绪态。
四、用信号量机制实现进程互斥
-
为什么要把互斥信号量mutex的初值设置为1?
答:信号量的初值其实表示的是系统中某种资源的数量,而临界区在一个时间段内也只能运行一个进程对它进行访问,所以我们可以把临界区也理解成一种特殊的资源,并且这个资源只有一个,也就是说临界区只能被分配给一个进程使用。只有这个进程释放了这个临界区资源之后,才能被其他进程访问。 -
在临界区之前执行P(mutex)
-
在临界区之后执行V(mutex)
-
P、V操作必须成对出现。缺少P(mutex)就不能保证临界资源的互斥访问。缺少V(mutex)会导致资源永不被释放,等待进程永不被唤醒。
五、用信号量机制实现进程同步
- 设置同步信号量S,初值为0
- 在“前操作”之后执行V(S)
- 在“后操作”之前执行P(S)
六、用信号量机制实现前驱关系
对于前驱图的理解:只有S1执行完之后,才能执行S2、S3。而只有S2执行完之后,才能执行S4、S5。剩下的以此类推。。。
其实,前驱关系可以看作是多层的同步关系
记住:
- 互斥问题,信号值初值为1(互斥访问临界区)
- 同步问题,信号值初值为0(进程间相互配合工作,遵循一定的先后顺序)