第九章 进程的同步与通信
9.1 同步的基本概念
共享资源
相互制约
P:生产者
C:消费者
一、临界资源和临界区
- 临界资源
一段时间内只允许一段进程访问的资源
- 临界区
程序中涉及到临界资源的代码段
- 准则
(1) 空闲让进。当无进程处于临界区时,表明临界资源处于空闲状态,应允许一个请 求进入临界区的进程立即进入自己的临界区,以有效地利用临界资源。
(2) 忙则等待。当已有进程进入临界区时,表明临界资源正在被访问,因而其它试图 进入临界区的进程必须等待,以保证对临界资源的互斥访问。
(3) 有限等待。对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界 区,以免陷入“死等”状态。
(4) 让权等待。当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入 “忙等”状态。
二、利用软件实现互斥
- 两个标志
- 一个指针
三、利用硬件实现互斥
加锁(互斥锁)
在对临界区进行管理时,可以将标志看做 一个锁,“锁开”进入,“锁关”等待,初始时锁是打开的。每个要进入临界区的进程必须 先对锁进行测试,当锁未开时,则必须等待,直至锁被打开。反之,当锁是打开的时候, 则应立即把其锁上,以阻止其它进程进入临界区。显然,为防止多个进程同时测试到锁为 打幵的情况,测试和关锁操作必须是连续的,不允许分开进行。
9.2 信号量机制
物理含义 |
|
正数 |
资源数量 |
负数 |
阻塞进程个数 |
一、整型信号量
把整型信号量定义为一个用于表示资源数目的整型量s,它与一般整型量不同,除初始化外,仅能通过两个标准的原子操作(Atomic Operation) wait(S)和signal(S)来访问。很长时间以来,这两个操作一直被分别称为P、V操作。wait和signal操作可描述如下:
1 wait (S){ 2 while (S<=^)); /*do no-op*/ 3 S--; 4 } 5 signal(S) 6 { 7 S++; 8 }
wait(S)和signal(S)是两个原子操作,因此,它们在执行时是不可中断的。
二、记录型信号量
在整型信号量机制中的wait操作,只要是信号量S<=0,就会不断地测试。因此,该机 制并未遵循“让权等待”的准则,而是使进程处于“忙等”的状态。记录型信号量机制则 是一种不存在“忙等”现象的进程同步机制。但在采取了“让权等待”的策略后,又会出 现多个进程等待访问同一临界资源的情况。为此,在信号量机制中,除了需要一个用于代 表资源数目的整型变量value外,还应增加一个进程链表指针list,用于链接上述的所有等 待进程。记录型信号量是由于它采用了记录型的数据结构而得名的。
wait(S) { S->value--; if(S->value<0) block(s->list); } signal(S) { S->value++; if(S->value<=0) wakeup(S->list); }
一、信号量的应用
1.利用信号量实现进程互斥
(1)信号量初值为1;
(2)P(wait)V(signal)成对出现
(3)紧邻临界区
2.实现前趋图
9.3 经典同步问题
一、生产者(P)消费者(C)问题
条件 |
制约关系 |
全空 |
P不做C不能做 |
全满 |
C不做P不能做 |
同一 |
P,C互斥 |
int in=0,out=0; item buffer[n]; int mutex=1,empty=n,full=0; void proceducer(){ do{ producer an item nextp; ... wait(empty); wait(mutex); buffer[in]=nextp; in=(in+1)%n; signal(mutex); signal(empty); }while(ture) } void customer(){ do{ wait(full); wait(mutex); nextc=buffer[out]; out=(out+1)%n; signal(mutex); signal(empty); customer the item in nextc; ... }while(ture) } void main(){ cobegin proceducer();consumer(); }
在生产者-消费者问题中应注意:首先,在每个程序中用于实现互斥的wait(mu tex)和 signal(mutex)必须成对地出现;其次,对资源信号量empty和full的wait和signal操作,同 样需要成对地出现,但它们分别处于不同的程序中。例如,wait( empty)在计算进程中,而 signal( empty)则在打印进程中,计算进程若因执行wait( empty)而阻塞,则以后将由打印进 程将它唤醒;最后,在每个程序中的多个 wait操作顺序不能颠倒。应先执行对资源信号量 的wait操作,然后再执行对互斥信号量的wait操作,否则可能引起进程死锁。