首页 > 技术文章 > 经典进程同步与互斥习题总结

henuliulei 2018-11-11 16:03 原文

基础知识导引

临界资源

      在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。但对于某些资源来说,其在同一时间只能被一个进程所占用。这些一次只能被一个进程所占用的资源就是所谓的临界资源。

   典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。

    对于临界资源的访问,必须是互诉进行。也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。而进程内访问临界资源的代码被成为临界区。

    对于临界区的访问过程分为四个部分:

    1.进入区:查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞

    2.临界区:在临界区做操作

    3.退出区:清除临界区被占用的标志

    4.剩余区:进程与临界区不相关部分的代码

互斥

    进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。

 比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。概念如图所示。

 

同步

    进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。

    比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。概念如图所示。

实现临界区互斥的基本方法

 硬件实现方法

  1 关中断。

  2利用Test-and-Set指令实现互斥

  3利用Swap指令实现进程互斥

信号量实现方式

    这也是我们比较熟悉P V操作。通过设置一个表示资源个数的信号量S,通过对信号量S的P和V操作来实现进程的的互斥。

    P和V操作分别来自荷兰语Passeren和Vrijgeven,分别表示占有和释放。P V操作是操作系统的原语,意味着具有原子性。

    P操作首先减少信号量,表示有一个进程将占用或等待资源,然后检测S是否小于0,如果小于0则阻塞,如果大于0则占有资源进行执行。

    V操作是和P操作相反的操作,首先增加信号量,表示占用或等待资源的进程减少了1个。然后检测S是否小于0,如果小于0则唤醒等待使用S资源的其它进程。

经典题总结

下面将以大量的篇幅总结最近所学和接触到的进程同步问题作出总结,难免有错误出现,还请包涵指出。

Q1:生产者和消费者

问题描述:一组生产者进程和消费者进程共享一个初始为空,大小为n的缓冲区。只有当缓冲区没满的时候,生产者才能将消息放进去。同理,只有当缓冲区不空的时候,消费者才能从中取消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,也只允许一个消费者拿出消息。这里我再解释一下,意思是,同一个时刻只能是一个生产者或者一个消费者操作缓冲区,禁止一下情况:多个生产者或者多个消费者操作缓冲区,同样,一个生产者和一个消费者同时操作也是禁止的。

分析:首先,生产者之间,消费者之间是互斥的关系,同时生产者消费者之间又是协同的关系,属于进程同步。

其次,设置信号量,我们知道信号量个数等于资源数,我们用empty=n表示缓冲区空的缓冲区数目,用full=0表示缓冲区满的缓冲区数目。同时,还要一个信号量mutex来实现,诸进程对缓冲区的互斥访问。
 1利用记录性信号量解决生产者-消费者问题

 1 int in=0,out=0;
 2 item buffer[n];
 3 semaphore mutex=1,empty=n,full=0;
 4 void proceducer(){
 5   do{ 
 6     producer an item nextp;
 7     ...
 8     wait(empty);
 9     wait(mutex);
10     buffer[in]=nextp;
11     in=(in+1)%n;
12     signal(mutex);
13     signal(full);
14   }while(true);
15 }
16 void consumer(){
17     do{
18         wait(full);
19         wait(mutex);
20         nextc=buffer[out];
21         out=(out+1)%n;
22         signal(mutex);
23         signal(empty);
24         consumer the item in nextc;
25     }while(true);
26 }
27 void main()
28 {
29     cobegin
30         proceducer(); consumer();
31     coend;
32 }

注意8和9行及18和19行的次序,写反会导致死锁

2利用and信号量解决生产者和消费者问题

通过Swait(empty,mutex)代替wait(empty)和wait(mutex).Signal(mutex,full)代替signal(mutex)和signal(full)

通过Swait(full,mutex)代替wait(full)和wait(mutex).Signal(mutex,empty)代替signal(mutex)和signal(empty)

 1 int in=0,out=0;
 2 item buffer[n];
 3 semaphore mutex=1,empty=n,full=0;
 4 void proceducer(){
 5   do{
 6     producer an item nextp;
 7     ...
 8     Swait(empty,mutex);
 9     buffer[in]=nextp;
10     in:=(in+1)%n;
11     Ssignal(mutex,full);
12   }while(true);
13 }
14 void consumer(){
15     do{
16         Swait(full,mutex);
17         nextc=buffer[out];
18         out:=(out+1)%n;
19         Ssignal(mutex,empty);
20         consumer the item in nextc;
21         ...
22     }while(true);
23 }
24 void main()
25 {
26     cobegin
27         proceducer(); consumer();
28     coend;
29 }

Q2哲学家进餐问题

问题描述:有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。

在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。

分析:筷子是临界资源,在一段时间内只允许一位哲学家使用,为实现筷子的互斥使用,可以使用一个信号量来表示一只筷子,这五个信号量构成信号量数组。

 1 semaphore chopsticks[5]={1,1,1,1,1};
 2 do{
 3     wait(chopsticks[i]);\
 4     wait(chopsticks[i+1]%5);
 5     ...
 6     //eat
 7     signal(chopsticks[i]);
 8     signal(chopsticks[i+1]%5);
 9     ...
10     //think
11     ...
12 }while(true)

 

下面是三种改进方法

      

方法一:添加一个控制人数的信号量

 1 semaphore chopsticks[5]={1,1,1,1,1};
 2 semaphore r=4;//设置一个信号量控制同时就餐的人数
 3 void philosopher(int i)
 4 {
 5 do{
 6     think();
 7     wait(r);
 8     wait(chopsticks[i]);
 9     wait(chopsticks[i+1]%5);
10     eat();
11     signal(chopsticks[i]);
12     signal(chopsticks[i+1]%5);
13     think();
14   }while(true)
15 }

方法二:利用and型信号量解决

 1 semaphore chopsticks[5]={1,1,1,1,1};
 2 void philosopher(int i)
 3 {
 4 do{
 5     think();
 6     Swait(chopsticks[i],chopsticks[i+1]%5);
 7     eat();
 8     Ssignal(chopsticks[i],chopsticks[i+1]%5);
 9     think();
10   }while(true)
11 }

方法三:

semaphore chopsticks[5]={1,1,1,1,1};
void philosopher(int i)
{
do{
    if(i%2==1){//奇数哲学家先左后右
        wait(chopsticks[i]);
        wait(chopsticks[i+1]%5);
        eat();
        signal(chopsticks[i]);
        signal(chopsticks[i+1]%5);
    }else{//偶数哲学家先右后左
        wait(chopsticks[i+1]);
        wait(chopsticks[i]%5);
        eat();
        signal(chopsticks[i+1]);
        signal(chopsticks[i]%5);
    }
  }while(true)
}

Q3读者写者问题

问题描述:有多个写者多个读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者在读文件时写者也不去能写文件,可同时有多个读者,但是同时只能有一个写者。

1读者优先

         

        

 

 1 semaphore wmutex=1,rmutex=1,readcount=0;
 2 void reader(){
 3     do{
 4         wait(rmutex);
 5         if(readcount==0)
 6             wait(wmutex);//如果已经有写者了,读者把自己堵塞在这,没有写者,读者进来写者将堵塞
 7          readcount++;
 8          signal(rmutex);
 9          read();
10          wait(rmutex);
11          readcount--;
12          if(readcount==0)
13                 signal(wmutex);
14          signal(rmutex);
15 
16     }while(true)
17 }
18 void writer()
19 {
20     do{
21         wait(wmutex);
22         write();
23         signal(wmutex);
24     }while(true)
25 
26 }

2写者优先

 

 

 1 semaphore wmutex=1,rmutex=1,readcount=0;
 2 semaphore s=1;
 3 void reader(){
 4     do{
 5         wait(s);    
 6         wait(rmutex);
 7         if(readcount==0)
 8             wait(wmutex);
 9          readcount++;
10          signal(rmutex);
11          signal(s);
12          read();
13          wait(rmutex);
14          readcount--;
15          if(readcount==0)
16                 signal(wmutex);
17          signal(rmutex);
18 
19     }while(true)
20 }
21 void writer()
22 {
23     do{
24         wait(s);    
25         wait(wmutex);//等待前面读者读完
26         write();
27         signal(wmutex);
28         signal(s);
29     }while(true)
30 
31 }

Q4 读者-写者问题的变形

问题描述:进程a进程b共享文件file,共享要求是:A,B可同时读file,或者同时写,但不允许一个在写,一个在读,既不允许同时进行

 1 semaphore wmutex=1,rmutex=1;
 2 semaphore s=1;
 3 int readcount=0;
 4 int writecount=0;
 5 void reader(){
 6     do{
 7         wait(rmutex);
 8         if(readcount==0)
 9             wait(s);//保证读写互斥
10          readcount++;
11          signal(rmutex);
12          read();
13          wait(rmutex);
14          readcount--;
15          if(readcount==0)
16                 signal(s);
17          signal(rmutex);
18     }while(true)
19 }
20 void writer()
21 {
22     do{
23         wait(wmutex);
24         if(writecount==0)
25             wait(s);//保证读写互斥
26          writecount++;
27          signal(wmutex);
28          write();
29          wait(wmutex);
30          writecount--;
31          if(writecount==0)
32                 signal(s);
33          signal(wmutex);
34     }while(true)
35 
36 }

Q5 在原始的读者-写者问题上,假设读者-最多有rn个读者同时读  

 1 semaphore L=RN;
 2 semaphore mx=1;
 3 void reader(){
 4     do{
 5         Swait(L,1,1);
 6         Swait(mx,1,0);//可控开关,mx=0表示写者在写,读者不可以读
 7         read();
 8         Signal(L,1);
 9         
10     }while(true)
11 }
12 void writer()
13 {
14     do{
15         Swait(mx,1,1;L,RN,0);//读者优先
16         //保证没有读者时可以写,并且写者在写的时候读者
17         write();
18         Ssignal(mx,1);
19     }while(true)
20 
21 }
22 void writer()
23 {
24     do{
25         Swait(mx,1,1);//写者优先
26         Swait(L,RN,0);
27         write();
28         Ssignal(mx,1);
29     }while(true)
30 
31 }

 

L保证了读者最多允许的读者个数,同时保证了写者在没有读者的情况下可以写。

mx保证了在写者写的情况下读者不可以读。

Q6 

1 若有一售票厅只能容纳300人,当少于300人时,可以进入;否则,需在外等候。若将每一个购票者作为一个进程,请用P(wait)、V(signal)操作编程,并写出信号量的初值。

 P(S); 进入售票厅; 购票; 退出售票厅; V(S); 

2若有一售票厅只能容纳300人,当少于300人时,可以进入;否则,需在外等候。若将每一个购票者作为一个进程,请用P(wait)、V(signal)操作编程,并写出信号量的初值。(强调:只有一个购票窗口,每次只能为一位购票者服务)

 1 semophore S1=330,S2=1 2 
 3     用户进程Pi {
 4 
 5                     Wait(S1)
 6 
 7                     进入大厅
 8 
 9                     Wait(S2)
10 
11                     窗口购票
12 
13                    退出购票窗口
14 
15                     Signal(S2)
16 
17                      退出大厅
18 
19                     Signal(S1)
20 
21 }

分析:对于上面的问题,问题二相对于问题一多了一个购票窗口,所以多了一个购票窗口信号量,该信号量是互斥信号量。

Q7

描述:有一个阅览室,读者进入时必须先在一张登记表上登记。该表中每个表项代表阅览室中的一个座位。读者离开时要销掉登记信息。阅览室共有50个座位。登记表每次仅允许一个读者登记或注销。读者登记时发现登记表满,在阅览室外等待,直至有空位再登记进入。试用P、V操作描述读者行为。

 1 semaphore s1=100,s2=1;
 2 读者进程pi(i=0,1,2,...)
 3 p(s1);
 4 p(s2);
 5 登记
 6 v(s2);
 7 阅览
 8 p(s2);
 9 撤销登记
10 v(s2)
11 v(s1)

Q8

描述: 设一辆公共汽车上,司机和售票员的活动分别是 :司机:启动车辆,正常行车,到站停车;售票 员:上乘客,,关车门,售票,开车门,下乘客.在汽车不断地到站,停车,行驶的过程中,这两个活动有什么同步关系?并用wait和signal原语操作实现它们的同步

 

 

 

 

 1 semaphore s1=0;
 2 semaphore s2=0; 3 main(){
 4     parbegin
 5       Driver();
 6       Conductor();
 7     parend
 8 }
 9 Driver()
10 {
11     p(s1);
12     启动车辆;
13     正常行车;
14     到站停车;
15     V(s2);
16 }
17 Conductor()
18 {
19    关车门;
20    V(s1);
21    售票;
22    p(s2);
23    开车门;
24    上下乘客;
25 }

Q9  : 有一只铁笼子,每次只能放入一只动物,猎手向笼中放入老虎,农民向笼中放入猪,动物园等待取笼中的老虎,饭店等待取笼中的猪,试用P、V操作写出能同步执行的程序

 

 1 猎手进程    农民进程    动物园进程    饭店进程

2  P(s)        P(s)        P(s1)          P(s2)

3 放入虎      放入猪        买老虎           买猪

4  V(s1)      V(s2)       V(s)            V(s) 

Q10 桌上有一空盘,允许存放一只水果。爸爸可向盘中放苹果,也可向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发线程的同步。

 1 semaphore s=1;
 2 semaphore so=0;
 3 semaphore sa=0;
 4 main()
 5 {
 6     cobegin
 7         father();
 8         son();
 9         daughter();
10     coend
11 }
12 son()
13 {
14     p(so);
15     从盘中取出橘子;
16     v(s);
17     吃橘子;
18 }
19 daughter()
20 {
21     p(sa);
22     从盘中取出苹果;
23     v(s);
24     吃苹果;
25 }
26 father()
27 {
28     p(s);
29     将水果放入盘中;
30     if(放入的是橘子) v(so);
31     else v(sa);
32 }

Q11用p,v原语实现三辆汽车s,e,w过丁字路口的过程(不考虑红绿灯)

 1 semaphore sa=1,sb=1,sc=1,sd=1;
 2 void procedureS(){
 3      p(sd);
 4      驶入D;
 5      p(sb);
 6      驶入B;
 7      v(sd);
 8      驶出D
 9      p(sa);
10      驶入A;
11      v(sb);
12      驶出B;
13      v(sa);
14      驶出A;
15 }
16 void procedureW(){
17      p(sc);
18      驶入C;
19      p(sd);
20      驶入D;
21      v(sc);
22      驶出C;
23      v(sd);
24      驶出D;
25 }
26 void procedureE(){
27      p(sb);
28      驶入B;
29      p(sa);
30      驶入A;
31      v(sb);
32      驶出B
33      p(sc);
34      驶入C;
35      v(sa);
36      驶出A;
37      v(sc);
38      驶出C;
39 }

Q12用wait.signal操作解决下图之同步问题,提示:分别考虑对缓冲区s和t的同步,再合并考虑

 

 

 1 semaphore sin=1,sout=0,tin=1,tout=0;
 2 void get()
 3 {
 4     while(1){
 5         wait(1);
 6         将数放入s;
 7         signal(sout);
 8     }
 9 }
10 void copy()
11 {
12     wait(sout);
13     wait(tin);
14     将数字从s取出放入T;
15     signal(tout);
16     signal(sin);
17 }
18 void put()
19 {
20     wait(tout);
21     将数从t取走;
22     signal(tin);
23 }

Q13

描述:

有一个仓库,可以存放A和B两种产品。要求:
1)每次只能存入一种产品(A或B);
2)−N<A产品数量−B产品数量<M。试用PV操作描述产品A与产品B的入库过程。

 1 Semaphore mutex=1,Sa=M-1,Sb=N-1 2 Process A()
 3 {
 4 While(1)
 5 {
 6 P(Sa);
 7 P(mutex);
 8 A入库;
 9 V(mutex);
10 V(Sb);
11 }
12 }
13 Process B()
14 {
15 While(1)
16 {
17 P(Sb);
18 P(mutex);
19 B入库;
20 V(mutex);
21 V(Sa);
22 }
23 }

 

Q14

进程A1、A2、…Anl通过m个缓冲区向进程B1、B2、…Bn2不断地发送消息。发送和接收工作遵循如下规则: (1)每个发送进程一次发送一个消息,写入一个缓冲区,缓冲区大小与消息长度一样。 (2)对于每一个消息,B1、B2、…Bn2都需各接收一次,读入自己的数据区内。 (3)m个缓冲区都满时,发送进程等待;没有可读的消息时,接收进程等待。 试用wait、signal操作描述它们的同步关系。

  

1

 

 1 A1:
 2      while(1){
 3         wait(sin[1]);
 4         wait(sin[2]);
 5         将数据放入缓冲区
 6         signal(sout[1])
 7         signal(sout[2]);
 8      }
 9 Bi:
10     while(1){
11         wait(sout[i]);
12         从缓冲区取数字;
13         signal(sin[i]);
14     }     

 

 2

 1 A1:
 2      while(1){
 3         wait(sin[1]);
 4         wait(sin[2]);
 5         wait(mutex);
 6         将数据放入缓冲区
 7         signal(mutex);
 8         signal(sout[1])
 9         signal(sout[2]);
10      }
11 Bi:
12     while(1){
13         wait(sout[i]);
14         wait(mutex);
15         从缓冲区取数字;
16         signal(mutex);
17         signal(sin[i]);
18     }     

 

3

 

 1 Aj:
 2      while(1){
 3         for(int i=1;i<=n2;i++)
 4         wait(sin[i]);
 5         wait(mutex);
 6         将数据放入缓冲区
 7         signal(mutex);
 8        for(int i=1;i<=n2;i++)
 9         signal(sout[i]);
10      }
11 Bi:
12     while(1){
13         wait(sout[i]);
14         wait(mutex);
15         从缓冲区取数字;
16         signal(mutex);
17         signal(sin[i]);
18     }     

Q15有桥如下图所示,车流如箭头所示,桥上不允许两车交汇,但允许同方向多辆车依次通过(即桥上可以有多个同方向的车)。用P、V操作实现交通管理以防止桥上堵塞

解析:这个题目要解决:南、北互斥(桥上不允许两车交汇,相当于“读、写互斥”),需要设置一个互斥信号量mutex,初值为1;南、南共享(相当于“读、读共享”),套用实现“读、读共享”的模式,需要设置一个共享变量southcount,用于记录当前桥上向南行驶过桥的车辆数目,初值为0,再设置一个互斥信号量smutex,实现对southcount的互斥访问;北、北共享(也相当于“读、读共享”),套用实现“读、读共享”的模式,同理可得。

 1 semaphore mutex = 1;// 作为桥的互斥访问信号量
 2 semaphore smutex = 1;// 作为southcount的互斥访问信号量
 3 semaphore nmutex = 1;// 作为northcount的互斥访问信号量
 4 int southcount = 0;// 记录南方向的车辆的数量
 5 int northcount = 0;// 记录北方向的车辆的数量
 6 void south()
 7 {
 8     while(true)
 9     {
10         wait(smutex);
11         if(southcount == 0)
12             wait(mutex);
13         southcount++;
14         signal(smutex);
15         // 南方车辆通过
16         wait(smutex);
17         southcount--;
18         if(southcount == 0)
19             signal(mutex);
20         signal(smutex);
21     }
22 }
23 void north()
24 {
25     while(true)
26     {
27         wait(nmutex);
28         if(northcount == 0)
29             wait(mutex);
30         northcount++;
31         signal(nmutex);
32         // 北方车辆通过
33         wait(nmutex);
34         northcount--;
35         if(northcount == 0)
36             signal(mutex);
37         signal(nmutex);
38     }
39 }

Q16某银行有人民币储蓄业务,由n个储蓄员负责。每个顾客进入银行后先取一个号,并且等着叫号。当一个储蓄人员空闲下来,就叫下一个号。请用P,V操作正确编写储蓄人员和顾客进程的程序。

 1 var customer_count,mutex:semaphore;     customer_count:=0;    mutex:=1; 
 2 cobegin 
 3 process customer 
 4      begin 
 5       L1: take a number;
 6            P(mutex0);
 7                  进入队列; 
 8           V(mutex); 
 9           V(customer_count);   
10           Go to L1;
11       End;
12 Process serversi(I=1,2,3,„)
13       Begin 
14        P(customer_count);
15        P(mutex);
16        从队列取号;
17          v(mutex);
18        为该客户服务
19      end
20 coend

Q17

请用信号量解决以下的“过独木桥”问题:同一方向的行人可连续过桥,当某一方向
有人过桥时,另一方向的行人必须等待;当某一方向无人过桥时,另一方向的行人可以过桥。
答:将独木桥的两个方向分别标记为 A 和 B;并用整型变量 countA,countB 分别表示 A、B 方
向上已在独木桥上的行人数,它们的初值为 0;再设置三个初值都为 1 的互斥信号量:SA 用来实现
对 countA 的互斥访问,SB 用来实现对 countB 的互斥访问,mutex 用来实现两个方向行人对独木桥
的互斥使用。则可将 A 方向行人的动作描述为

 1 var SA,SB,mutext:semaphore:=1,1,1; 
 2  countA,countB:integer:=0,0; 
 3 begin 
 4 parbegin 
 5  process AtoB:beging 
 6  repeat 
 7 wait(SA); 
 8 if(countA=0) then wait(mutex); 
 9 countA := countA+1; 
10 signal(SA); 
11 通过独木桥;
12 wait(SA); 
13 countA := countA-1; 
14 I f(countA=0) then signal(mutex); 
15 signal(SA); 
16  until false 
17  end 
18  process BtoA:beging 
19  repeat 
20 wait(SB); 
21 if(countB=0) then wait(mutex); 
22 countB := countB+1; 
23 signal(SB); 
24 通过独木桥;
25 wait(SB); 
26 countB := countB-1; 
27 I f(countB=0) then signal(mutex); 
28 signal(SB); 
29  until false 
30  end 
31 parend 
32 end 

Q18理发师问题

假设有一个理发店只有一个理发师,一张理发时坐的椅子,若干张普通椅子顾客供等候时
坐。没有顾客时,理发师就坐在理发的椅子上睡觉。顾客一到,他不是叫醒理发师,就是
离开。如果理发师没有睡觉,而在为别人理发,他就会坐下来等候。如果所有的枯木都坐
满了人,最后来的顾客就会离开

分析:

最常见的解决方案就是使用三个信号标(Semaphore):一个给顾客信号标,一个理发师信
号标(看他自己是不是闲着),第三个是互斥信号标(Mutual exclusion,缩写成
mutex)。一位顾客来了,他想拿到互斥信号标,他就等着直到拿到为止。顾客拿到互斥信
号标后,会去查看是否有空着的椅子(可能是等候的椅子,也可能是理发时坐的那张椅
子)。
如果没有一张是空着的,他就走了。如果他找到了一张椅子,就会让空椅子的数量减少一
张()标。这位顾客接下来就使用自己的信号标叫醒理发师。这样,互斥信号标就释放出
来供其他顾客或理发师使用。如果理发师在忙,这位顾客就会等。理发师就会进入了一个
永久的等候循环,等着被在等候的顾客唤醒。一旦他醒过来,他会给所有在等候的顾客发
信号,让他们依次理发

 1 顾客信号标=0
 2 理发师信号标=0
 3 互斥信号标=1
 4 int 空椅子数量=N
 5 理发师(线程/进程)
 6 while(true)
 7 {
 8     p(顾客)//试图为一位股客服务,没有就睡觉
 9     p(互斥信号标)//这时被叫醒,要修改椅子的数量
10       空椅子数量++//一张椅子被空出去
11     v(理发师)//理发师开始去理发
12     v(互斥信号标)//我们不想司锁在椅子上,这时理发师开始理发
13 }
14 顾客(线程/进程)
15       while(true )  //持续不断地循环
16       P(互斥信号标)  //想坐到一张椅子上
17       if (空椅子数量>0) { //如果还有空着的椅子的话
18       空椅子数量--  //顾客坐到一张椅子上了
19       V(顾客)  //通知理发师,有一位顾客来了
20       V (互斥信号标)  //不会死锁到椅子.上
21       P (理发师)  //该这位顾客理发了,如果他还在忙,那么他就等着
22             //这时顾客在理发}
23       else{  //没有空着的椅子
24               //不好彩
25       V (互斥信号标)  //不要忘记释放被锁定的椅子
26                 //顾客没有理发就走了
27       }
28  }

 

Q19三个烟鬼

假设一支香烟需要:1、烟草;2、卷烟纸;3、一根火柴。
假设一张圆桌上围座着三烟鬼。他们每个人都能提供无穷多的材料:一个有无穷多的烟
草;一个有无穷多的卷烟纸;一个有无穷多的火柴。
假设还有一个不吸烟的协调人。他每次都会公正地要求两个人取出一份材料放到桌,然后
通知第三个人。第三个人从桌上拿走另外两个人的材料,再加上自己的一份,卷一枝烟就
会抽起来。这时,协调人看到桌上空了,就会再次随机叫两人向桌上贡献自己的材料。这
个过程会无限地进行下去。
不会有人把桌上的东西藏起来。只有当他抽完一枝烟后,才会再卷另一枝。如果协调人将
烟草和卷烟纸放到桌上,而那个有火柴的人仍在吸烟,那么烟草、卷烟纸就会原封不动地
放在桌上,走到有火柴的人抽完烟取走桌上的材料

 1 while(true){
 2      wait(T);//烟的数量已经被吸
 3       公平的随机选择烟鬼i和j,第三个为k;
 4      signal(A[k]); //烟的材料凑齐
 5 }
 6 烟鬼的代码
 7 while(true){
 8      wait(A[i]);//卷一支烟
 9 10      signal(T); //可吸的烟加一
11 }

 

推荐阅读