1.进程同步
两种形式的制约关系
1.简介相互制约的关系,由于系统的资源共享,只能互斥的访问某个系统资源。
2.直接相互制约的关系(同步关系)两个或者多个进程通过合作完成同一任务,进程间的制约关系就是源于它们之间的合作。(生产者消费者问题)
2.临界资源
打印机,磁带机等,进程在使用它们时都需要采用互斥的方式,这样的资源叫做临界资源
3.生产者-消费者问题
生产者-消费者问题的本质就是对于临界资源互斥访问的一个问题。
问题描述
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。
生产者、消费者共享一个初始为空、大小为n的缓冲区。
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。(缓冲区没满——>生产者生产)
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。(缓冲区没空——>消费者消费)
缓冲区是临界资源,各进程必须互斥地访问。(互斥关系)
![](https://i-blog.csdnimg.cn/blog_migrate/a56d8a533d2471adc93260299ef6b93c.png)
相邻的pv操作顺序时不易改变的,不然容易出现死锁等状态。
① -> ② -> ③
若此时缓冲区内已经放满产品,则empty=0,full=n。
则生产者进程执行①使mutex变为0,再执行②,由于已没有空闲缓冲区,因此生产者被阻塞。由于生产者阻塞,因此切换回消费者进程。消费者进程执行③,由于mutex为0,即生产者还没释放对临界资源的“锁”,因此消费者也被阻塞。这就造成了生产者等待消费者释放空闲缓冲区,而消费者又等待生产者释放临界区的情况,生产者和消费者循环等待被对方唤醒,出现“死锁”。
③ -> ④ -> ①
同样的,若缓冲区中没有产品,即full=0,empty=n。按③④①的顺序执行就会发生死锁。
因此,实现互斥的P操作一定要在实现同步的P操作之后。
V操作不会导致进程阻塞,因此两个V操作顺序可以交换。
多生产者-多消费者 模型
桌子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果
![](https://i-blog.csdnimg.cn/blog_migrate/c469a4ccb7caf718208c77985bb38ece.png)
![](https://i-blog.csdnimg.cn/blog_migrate/21b22c0d911425ffd8bca2bf6acaf8ee.png)
如果不设置互斥信号量的话,那么父亲和母亲可以同时的往盘子中放水果,则盘子中的东西则会被覆盖,这样就会出现数据覆盖的情况。
4.临界区问题
临界区问题的本质就是,对于一个临界资源进行检查,如果该资源空闲,则可以进行访问,并将访问标志设置为正在访问,如果要访问的临界资源正在被访问的话,则进入等待队列。同时一个临界资源被某个进程运用完成以后还需要把访问标志设置为“空闲”。为了达成上诉的目标,则还需要在临界资源前加入一个进入区,在临界资源后面加入一个退出区。
为了实现进程能够互斥的进入自己的临界区,则需要满足以下几个规则
(1)空闲让进:当无进程在临界区时,应允许一个请求进入临界区的进程立即进去临界区
(2)忙则等待:当要访问的临界资源处于正在访问的状态,则试图进入的临界资源必须进行等待。
(3)有限等待:则必须保证进程在有限的时间内能访问临界区,即不会出现“饥饿”的情况
(4)让权等待:当进程不能进入自己的临界区时,应该立即释放处理机,避免出现“忙等”的状态。
5.软件同步机制
Peterson解决方案
举个例子:turn = i,表示轮到Pi进入临界区。那么上面这个代码就可以理解为:首先,Pi想进入临界区(flag[i] = True),然后,还是和前面的代码一样,Pi会先把进入临界区的机会让给Pj(turn = j),同样地,当Pj想进入临界区时,也会将进入临界区的权利先让给Pi。紧接着,变量turn的作用就显现出来了,当Pj把进入临界区的机会又让给Pi的时候(注意:这是发生在Pi将进入临界区的优先权让给Pj之后),Pi这次就会直接进入临界区。就不会再次出现一直互相谦让,最终导致均无法进入临界区的情况了。
Pi进程:
flag[i]= True;
turn= j;
while(flag[j]&& turn == j);
criticalsection;
flag[i]= False;
remaindersection;
Pj进程:
flag[j]= True;
turn= i;
while(flag[i]&& turn == i);
criticalsection;
flag[j]= False;
remaindersection;
6.硬件同步机制
1.关中断
进入锁测试时,关掉中断,计算机系统就不会产生中断从而不会发生进程调度。
(1)关中断权力大,产生后果严重(2)会影响cpu运行的效率(3)不适用于多cpu系统
2.利用Test-and-Set指令
进入临界区之前先检查,lock变量,如果为flase表示临界区空闲可以进入,如果lock变量的值为ture则表示临界区正在被使用,则继续循环检查lock变量,当进入临界区之后,再把lock变量的值设置为ture。
3.利用swap指令实现进程互斥
变量key的值为ture key和lock变量一直交换,只有当key为flase才能进入临界区 (当有一个进程被访问时,其他临界区资源就要不停的检测不符合让权等待)
7.信号量机制
整型信号量
通过p v操作来实现,p就是wait减少一个临界区资源,v就是single操作,释放一个临界区资源
记录行信号量
AND型信号量
用于处理一个进程,需要两个或更多的共享资源,如果有一个的临界区资源不大于等一的话,就全部资源都不给该进程进行分配,释放的话也是全部资源一起释放。
信号量集
当所申请的资源数量小于某一下限,则必须进行管制,不进行资源的分配。
8 信号量的应用
利用信号量实现进程互斥
为每个临界资源设置一个互斥信号量 mutex , 其初值为 1 ;
各进程访问该资源前执行 wait(mutex) 操作,离开临界区时执行 signal (mutex) 操作。
利用信号量实现进程同步
设置同步信号量的初始值为0,假设有c1和c2两个进程,c2必须在c1运行完后才能接着运行,则c2前面加个wait操作,在c1后面加个single操作,只有当c1single了同步信号量的值为1时c2才能进行操作。一般来说single和wait操作处于两个不同的进程。
9.管程
管程当中定义了共享数据结构只能被管程内部定义的函数所修改,所以如果我们想修改管程内部的共享数据结构的话,我们只能调用管程内部提供的函数来间接的修改这些数据结构。
管程每次只允许一个进程进入管程
管程内部虽然定义了很多函数,但是同一时刻一定只有一个进程使用管程中的一个函数,别的进程如果也想使用管程内部的某个函数的话,只要之前的进程还没有用完,别的进程就暂时不能执行管程的这些函数。