进程同步之信号量机制(pv操作)及三个经典同步问题

2023-11-19

 

1.信号量机制

信号量机制即利用pv操作来对信号量进行处理。

什么是信号量?信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。

当它的值大于0时,表示当前可用资源的数量;

当它的值小于0时,其绝对值表示等待使用该资源的进程个数。

注意,信号量的值仅能由PV操作来改变。

     一般来说,信号量S³0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S£0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。

 

2.PV操作

什么是PV操作?

p操作(wait):申请一个单位资源,进程进入

经典伪代码

wait(S){  
    while(s<=0)<span style="white-space:pre">    </span>//如果没有资源则会循环等待;  
        ;  
    S-- ;  
}  

v操作(signal):释放一个单位资源,进程出来

signal(S){  
    S++ ;  
} 

p操作(wait):申请一个单位资源,进程进入

v操作(signal):释放一个单位资源,进程出来

PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:
    P(S):①将信号量S的值减1,即S=S-1;
           ②如果S<=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
    V(S):①将信号量S的值加1,即S=S+1;
           ②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。

 

PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

 

 

 

使用PV操作实现进程互斥时应该注意的是:
    (1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
    (2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
    (3)互斥信号量的初值一般为1。

 

3.三个经典同步问题

前面我们讲到信号量机制,下面我们讲解利用信号量及PV操作解决几个经典同步问题。

a.生产者-消费者(缓冲区问题)

生产者一消费者问题(producer-consumerproblem)是指若干进程通过有限的共享缓冲区交换数据时的缓冲区资源使用问题。假设“生产者”进程不断向共享缓冲区写人数据(即生产数据),而“消费者”进程不断从共享缓冲区读出数据(即消费数据);共享缓冲区共有n个;任何时刻只能有一个进程可对共享缓冲区进行操作。所有生产者和消费者之间要协调,以完成对共享缓冲区的操作。

 

生产者进程结构:

do{  
     wait(empty) ;  
     wait(mutex) ;  
      
     add nextp to buffer  
      
     signal(mutex) ;  
     signal(full) ;  
}while(1) ;

消费者进程结构:

do{  
     wait(full) ;  
     wait(mutex) ;  
      
     remove an item from buffer to nextp  
      
     signal(mutex) ;  
     signal(empty) ;  
}while(1) ; 

我们可把共享缓冲区中的n个缓冲块视为共享资源,生产者写人数据的缓冲块成为消费者可用资源,而消费者读出数据后的缓冲块成为生产者的可用资源。为此,可设置三个信号量:full、empty和mutex。其中:full表示有数据的缓冲块数目,初值是0;empty表示空的缓冲块数初值是n;mutex用于访问缓冲区时的互斥,初值是1。实际上,full和empty间存在如下关系:full + empty = N

 

注意:这里每个进程中各个P操作的次序是重要的。各进程必须先检查自己对应的资源数在确信有可用资源后再申请对整个缓冲区的互斥操作;否则,先申请对整个缓冲区的互斥操后申请自己对应的缓冲块资源,就可能死锁。出现死锁的条件是,申请到对整个缓冲区的互斥操作后,才发现自己对应的缓冲块资源,这时已不可能放弃对整个缓冲区的占用。如果采用AND信号量集,相应的进入区和退出区都很简单。如生产者的进入区为Swait(empty,mutex),退出区为Ssignal(full,mutex)。

b.作者读者问题

读者一写者问题(readers-writersproblem)是指多个进程对一个共享资源进行读写操作的问题。

假设“读者”进程可对共享资源进行读操作,“写者”进程可对共享资源进行写操作;任一时刻“写者”最多只允许一个,而“读者”则允许多个。即对共享资源的读写操作限制关系包括:“读—写,互斥、“写一写”互斥和“读—读”允许。


我们可认为写者之间、写者与第一个读者之间要对共享资源进行互斥访问,而后续读者不需要互斥访问。为此,可设置两个信号量Wmutex、Rmutex和一个公共变量Rcount。其中:Wmutex表示“允许写”,初值是1;公共变量Rcount表示“正在读”的进程数,初值是0;Rmutex表示对Rcount的互斥操作,初值是1。


在这个例子中,我们可见到临界资源访问过程的嵌套使用。在读者算法中,进入区和退出区又分别嵌套了一个临界资源访问过程。

对读者一写者问题,也可采用一般“信号量集”机制来实现。如果我们在前面的读写操作限制上再加一个限制条件:同时读的“读者”最多R个。这时,可设置两个信号量Wmutex和Rcount。其中:Wmutex表示“允许写”,初值是¨Rcount表示“允许读者数目”,初值为R。为采用一般“信号量集”机制来实现的读者一写者算法。

 

 

c.哲学家进餐问题



(1) 在什么情况下5 个哲学家全部吃不上饭? 
考虑两种实现的方式,如下: 
A. 
算法描述: 

void philosopher(int i) /*i:哲学家编号,从0 到4*/   
{   
    while (TRUE) {   
        think( ); /*哲学家正在思考*/   
        take_fork(i); /*取左侧的筷子*/   
        take_fork((i+1) % N); /*取左侧筷子;%为取模运算*/   
        eat( ); /*吃饭*/   
        put_fork(i); /*把左侧筷子放回桌子*/   
        put_fork((i+1) % N); /*把右侧筷子放回桌子*/   
    }   
}   

分析:假如所有的哲学家都同时拿起左侧筷子,看到右侧筷子不可用,又都放下左侧筷子, 
等一会儿,又同时拿起左侧筷子,如此这般,永远重复。对于这种情况,即所有的程序都在 
无限期地运行,但是都无法取得任何进展,即出现饥饿,所有哲学家都吃不上饭。 
B. 
算法描述: 
规定在拿到左侧的筷子后,先检查右面的筷子是否可用。如果不可用,则先放下左侧筷子, 
等一段时间再重复整个过程。 
分析:当出现以下情形,在某一个瞬间,所有的哲学家都同时启动这个算法,拿起左侧的筷 
子,而看到右侧筷子不可用,又都放下左侧筷子,等一会儿,又同时拿起左侧筷子……如此 
这样永远重复下去。对于这种情况,所有的程序都在运行,但却无法取得进展,即出现饥饿, 
所有的哲学家都吃不上饭。 
(2) 描述一种没有人饿死(永远拿不到筷子)算法。 
考虑了四种实现的方式(A、B、C、D): 
A.原理:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释 
放出他所使用过的两支筷子,从而可使更多的哲学家进餐。以下将room 作为信号量,只允 
许4 个哲学家同时进入餐厅就餐,这样就能保证至少有一个哲学家可以就餐,而申请进入 
餐厅的哲学家进入room 的等待队列,根据FIFO 的原则,总会进入到餐厅就餐,因此不会 
出现饿死和死锁的现象。 
伪码: 

 

semaphore chopstick[5]={1,1,1,1,1};  
semaphore room=4;   
void philosopher(int i)   
{   
    while(true)   
    {   
        think();   
        wait(room); //请求进入房间进餐   
        wait(chopstick[i]); //请求左手边的筷子   
        wait(chopstick[(i+1)%5]); //请求右手边的筷子   
        eat();   
        signal(chopstick[(i+1)%5]); //释放右手边的筷子   
        signal(chopstick[i]); //释放左手边的筷子   
        signal(room); //退出房间释放信号量room   
    }   
}   

 

B.原理:仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。 
方法1:利用AND 型信号量机制实现:根据课程讲述,在一个原语中,将一段代码同时需 
要的多个临界资源,要么全部分配给它,要么一个都不分配,因此不会出现死锁的情形。当 
某些资源不够时阻塞调用进程;由于等待队列的存在,使得对资源的请求满足FIFO 的要求, 
因此不会出现饥饿的情形。 
伪码: 

semaphore chopstick[5]={1,1,1,1,1};   
void philosopher(int I)   
{   
    while(true)   
    {   
        think();   
        Swait(chopstick[(I+1)]%5,chopstick[I]);   
        eat();   
        Ssignal(chopstick[(I+1)]%5,chopstick[I]);   
    }   
}   

 

方法2:利用信号量的保护机制实现。通过信号量mutex对eat()之前的取左侧和右侧筷 
子的操作进行保护,使之成为一个原子操作,这样可以防止死锁的出现。 
伪码: 

 

semaphore mutex = 1 ;   
semaphore chopstick[5]={1,1,1,1,1};   
void philosopher(int I)   
{   
    while(true)   
    {   
        think();   
        wait(mutex);   
        wait(chopstick[(I+1)]%5);   
        wait(chopstick[I]);   
        signal(mutex);   
        eat();   
        signal(chopstick[(I+1)]%5);   
        signal(chopstick[I]);   
    }   
}   

 

C. 原理:规定奇数号的哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号 
的哲学家则相反.按此规定,将是1,2号哲学家竞争1号筷子,3,4号哲学家竞争3号筷子.即 
五个哲学家都竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一个哲学家能获 
得两支筷子而进餐。而申请不到的哲学家进入阻塞等待队列,根FIFO原则,则先申请的哲 
学家会较先可以吃饭,因此不会出现饿死的哲学家。 
伪码: 

 

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

 

D.利用管程机制实现(最终该实现是失败的,见以下分析): 
原理:不是对每只筷子设置信号量,而是对每个哲学家设置信号量。test()函数有以下作 
用: 
a. 如果当前处理的哲学家处于饥饿状态且两侧哲学家不在吃饭状态,则当前哲学家通过 
test()函数试图进入吃饭状态。 
b. 如果通过test()进入吃饭状态不成功,那么当前哲学家就在该信号量阻塞等待,直到 
其他的哲学家进程通过test()将该哲学家的状态设置为EATING。 
c. 当一个哲学家进程调用put_forks()放下筷子的时候,会通过test()测试它的邻居, 
如果邻居处于饥饿状态,且该邻居的邻居不在吃饭状态,则该邻居进入吃饭状态。 
由上所述,该算法不会出现死锁,因为一个哲学家只有在两个邻座都不在进餐时,才允 
许转换到进餐状态。 
该算法会出现某个哲学家适终无法吃饭的情况,即当该哲学家的左右两个哲学家交替 
处在吃饭的状态的时候,则该哲学家始终无法进入吃饭的状态,因此不满足题目的要求。 
但是该算法能够实现对于任意多位哲学家的情况都能获得最大的并行度,因此具有重要 
的意义。 
伪码: 

 

#define N 5 /* 哲学家人数*/   
#define LEFT (i-1+N)%N /* i的左邻号码 */   
#define RIGHT (i+1)%N /* i的右邻号码 */   
typedef enum { THINKING, HUNGRY, EATING } phil_state; /*哲学家状态*/   
monitor dp /*管程*/   
{   
    phil_state state[N];   
    semaphore mutex =1;   
    semaphore s[N]; /*每个哲学家一个信号量,初始值为0*/   
    void test(int i)   
    {   
        if ( state[i] == HUNGRY &&state[LEFT(i)] != EATING && state[RIGHT(i)] != EATING )   
        {   
            state[i] = EATING;   
            V(s[i]);   
        }   
    }   
    void get_forks(int i)   
    {   
        P(mutex);   
        state[i] = HUNGRY;   
        test(i); /*试图得到两支筷子*/   
        V(mutex);   
        P(s[i]); /*得不到筷子则阻塞*/   
    }   
    void put_forks(int i)   
    {   
        P(mutex);   
        state[i]= THINKING;   
        test(LEFT(i)); /*看左邻是否进餐*/   
        test(RIGHT(i)); /*看右邻是否进餐*/   
        V(mutex);   
    }   
}   

 

哲学家进程如下: 

 

void philosopher(int process)  
{   
    while(true)   
    {   
        think();   
        get_forks(process);   
        eat();   
        put_forks(process);   
    }   
}   

 

看完上面想必大家有点转晕了,来几道题,熟悉下。

 

 

【例1】生产者-消费者问题
在多道程序环境下,进程同步是一个十分重要又令人感兴趣的问题,而生产者-消费者问题是其中一个有代表性的进程同步问题。下面我们给出了各种情况下的生产者-消费者问题,深入地分析和透彻地理解这个例子,对于全面解决操作系统内的同步、互斥问题将有很大帮助。

(1)一个生产者,一个消费者,公用一个缓冲区。
定义两个同步信号量:
empty——表示缓冲区是否为空,初值为1。
   full——表示缓冲区中是否为满,初值为0。
生产者进程
while(TRUE){
生产一个产品;
     P(empty);
     产品送往Buffer;
     V(full);
}
消费者进程
while(True){
P(full);
   从Buffer取出一个产品;
   V(empty);
   消费该产品;
   }
(2)一个生产者,一个消费者,公用n个环形缓冲区。
定义两个同步信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。

    设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指
,指向下一个可用的缓冲区。
生产者进程
while(TRUE){
     生产一个产品;
     P(empty);
     产品送往buffer(in);
     in=(in+1)mod n;
     V(full);
}

消费者进程
while(TRUE){
 P(full);
   从buffer(out)中取出产品;
   out=(out+1)mod n;
   V(empty);
   消费该产品;
   }
(3)一组生产者,一组消费者,公用n个环形缓冲区
    在这个问题中,不仅生产者与消费者之间要同步,而且各个生产者之间、各个消费者之间还必须互斥地访问缓冲区。
定义四个信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。

    设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。
生产者进程
while(TRUE){
     生产一个产品;
     P(empty);
     P(mutex1);
     产品送往buffer(in);
     in=(in+1)mod n;
     V(mutex1);
     V(full);
}
消费者进程
while(TRUE){
 P(full)
   P(mutex2);
   从buffer(out)中取出产品;
   out=(out+1)mod n;
   V(mutex2);
   V(empty);
   消费该产品;
   }
  需要注意的是无论在生产者进程中还是在消费者进程中,两个P操作的次序不能颠倒。应先执行同步信号量的P操作,然后再执行互斥信号量的P操作,否则可能造成进程死锁。

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

分析在本题中,爸爸、儿子、女儿共用一个盘子,盘中一次只能放一个水果。当盘子为空时,爸爸可将一个水果放入果盘中。若放入果盘中的是桔子,则允许儿子吃,女儿必须等待;若放入果盘中的是苹果,则允许女儿吃,儿子必须等待。本题实际上是生产者-消费者问题的一种变形。这里,生产者放入缓冲区的产品有两类,消费者也有两类,每类消费者只消费其中固定的一类产品。

    :在本题中,应设置三个信号量S、So、Sa,信号量S表示盘子是否为空,其初值为l;信号量So表示盘中是否有桔子,其初值为0;信号量Sa表示盘中是否有苹果,其初值为0。同步描述如下:
int S=1;
int Sa=0;
int So=0;
      main()
      {
        cobegin
            father();      /*父亲进程*/
            son();        /*儿子进程*/
            daughter();    /*女儿进程*/
        coend
    }
    father()
    {
        while(1)
          {
            P(S);
            将水果放入盘中;
            if(放入的是桔子)V(So);
            else  V(Sa);
           }
     }
    son()
    {
        while(1)
          {
             P(So);
             从盘中取出桔子;
             V(S);
             吃桔子;
            }
    }
    daughter()
    {
         while(1)
            {
              P(Sa);
              从盘中取出苹果;
              V(S);
              吃苹果;
            }

 
思考题:

四个进程A、B、C、D都要读一个共享文件F,系统允许多个进程同时读文件F。但限制是进程A和进程C不能同时读文件F,进程B和进程D也不能同时读文件F。为了使这四个进程并发执行时能按系统要求使用文件,现用PV操作进行管理,请回答下面的问题:
    (1)应定义的信号量及初值:                    。
    (2)在下列的程序中填上适当的P、V操作,以保证它们能正确并发工作:
     A()                B()                  C()                 D()
      {                 {                    {                  {
      [1];                [3];                  [5];                 [7];
      read F;             read F;                read F;              read F;
     [2];                [4];                  [6];                 [8];
      }                  }                    }                  } 

    思考题解答:
(1)定义二个信号量S1、S2,初值均为1,即:S1=1,S2=1。其中进程A和C使用信号量S1,进程B和D使用信号量S2。
(2)从[1]到[8]分别为:P(S1) V(S1) P(S2) V(S2) P(S1) V(S1) P(S2) V(S2)

 

1、测量控制系统中的数据采集任务把所采集的数据送一单缓冲区;计算任务则 从该缓冲区中取出数据并进行计算。试写出利用信号量机制实现两者共享单缓冲区的同步算法。

       Var Sempty,Sfull: semaphore:= 1,0

Begin

              Parbegin

              Collection:begin

              repeat

                     采集一个数据;

                     wait(Sempty);

                     数据放入缓冲区;

                     signal(Sfull);

              untill false;

              end;

              Compute:begin

              repeat

                     wait(Sfull);

                     从缓冲区取出数据;

                     signal(Sempty);

                     计算;

`                    until false;

                     end;

              Parend

       End

2、有一阅览室,共有100个座位。读者进入时必须先在一种登记表上登记,该表为每一座位列一个表目,包括座号和读者姓名。读者离开时要注销掉登记内容。试用wait和signal原语描述读者进程的同步问题。

       var mutex, readcount :semaphore := 1,100;

Begin

              Parbegin

              Process Reader:begin

              repeat

              wait(readcount);

              wait(mutex);

              <填入座号和姓名完成登记>;

              signal(mutex);

<阅读>

              wait(mutex)

       <删除登记表中的相关表项,完成注销>

              signal(mutex);

              signal(readcount);

              until false;

              end;

              parend;

       End;

1)、桌上有一空盘,只允许放一个水果,爸爸专向盘中放苹果,妈妈专向盘中放桔子;女儿专吃盘中的苹果,儿子专吃盘中的桔子;试用wait和signal原语实现爸爸、妈妈、女儿、儿子之间的同步问题。

var Sempty, Sapple, Sorange,: semaphore:= 1,0,0;

 begin

       parbegin

              Father: begin

                            repeat

                                   wait(Sempty);                                <put apple in tray>;

                                   signal(Sapple);                         until false;

                       end;

              Mother: begin

                            repeat

                                   wait(Sempty);                                <put orange in tray>;

                                   signal(Sorange);                       until false;

                        end;

              Son: begin

                            repeat

                                   wait(Sorange);

                                   <take orange>;

                                   signal(Sempty);

                            until false;

                      end;

              Daughter: begin

                            repeat

                                   wait(Sapple);

                                   <take apple>;

                                   signal(Sempty);                       until false;

                       end;

              parend;

end;

1、在4×100米接力赛中,4个运动员之间存在如下关系,运动员1跑到终点把接力棒交给运动员2;运动员2一开始处于等待状态,在接到运动员1传来的接力棒后才能往前跑,他跑完100米后交给运动员3,运动员3也只有在接到运动员2传来的棒后才能跑,他跑完100米后交给运动员4,运动员4接到棒后跑完全程。请试用信号量机制对其上过程进行分析。

        

       var s1,s2,s3:semaphpre:=0,0,0;

       begin

              parbegin

                     Athlete1: begin

                                   Run100m;

                                   signal(s1);

                                end;

                     Athlete2: begin

                                   wait(s1);

                                   Run100m;

                                   signal(s2);

                                end;

                     Athlete3: begin

                                   wait(s2);

                                   Run100m;

                                   signal(s3);

                                end;

                     Athlete4: begin

                                   wait(s3);

                                   Run100m;

                                end;

              parend;

       end

 

2、在公共汽车上,司机和售票员各行其职,司机负责开车和到站停车;售票员负责售票和开、关车门;当售票员关好车门后驾驶员才能开车行驶。试用wait和signal操作实现司机和售票员的同步。

var s1,s2:semaphore:=0,0;

begin

       parbegin

              Process Driver

              begin

              repeat

                     <go right>;

                     <stop bus>;

                     signal(s2);

                     wait(s1);

              until false;

              end;

              Process BookingClerk;

              begin

              repeat

                     <ticketing>;

                     wait(s2);

                     <open the door>;

                     <close the door>;

                     signal(s1);

              until false

              end;

       parend;

end;

1、假设有3个并发进程P,Q,R,其中P负责从输入设备上读入信息,并传送给Q,Q将信息加工后传送给R,R负责打印输出。进程P,Q共享一个有m个缓冲区组成的缓冲池;进程Q,R共享一个有n个缓冲区组成的缓冲池(假设缓冲池足够大,进程间每次传输信息的单位均小于等于缓冲区长度),请写出满足上述条件的并发程序。(12分)

var mutex1,mutex2,Sip,Siq,Soq,Sor:semaphore:=1,1,m,0,n,0;

begin

       parbegin

              Process P

              begin

              repeat

                     <读入信息>

                     wait(Sip);

                     wait(mutex1);

                     <数据放入缓冲区>

                     signal(mutex1);

                     signal(Siq);

              until false

              end;

              Process Q

              begin

              repeat

                     wait(Siq);

                     wait(mutex1);

                     <从缓冲区中取出数据>

                     signal(mutex1);

                     signal(Sip);

                     <数据处理〉

                     wait(Soq);

                     wait(mutex2);

                     <处理后的数据放入缓冲区>

                     signal(mutex2);

                     signal(Sor);

              until false

              end;

              Process R

              repeat

                     wait(Sor);

                     wait(mutex2);

              <把数据送入打印机完成打印>;

                     signal(mutex2);

                     signal(Soq);

              until false

              end

       parend

end

 

2、有一只铁笼子,每次只能放入一只动物,猎手向笼子里放入老虎,农民向笼子里放入猪;动物园等待取笼子里的老虎,饭店等待取笼子里的猪。现请用wait和signal操作写出能同步执行的程序。

var Sempty, Stiger, Spig,: semaphore:= 1,0,0;  

begin

       parbegin

              Hunter: begin

                            repeat

                                   wait(Sempty);

                                   <put tiger in cage>;

                                   signal(Stiger);

                            until false;

                       end;

              Farmer: begin

                            repeat

                                   wait(Sempty);

                                   <put pig in cage>;

                                   signal(Spig);

                            until false;

                        end;

              Zoo: begin

                            repeat

                                   wait(Stiger);

                                   <take tiger>;

                                   signal(Sempty);

                            until false;

                      end;

              Hotel: begin

                            repeat

                                   wait(Spig);

                                   <take pig>;

                                   signal(Sempty);         until false;

                       end;

              parend;

end;

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

进程同步之信号量机制(pv操作)及三个经典同步问题 的相关文章

  • Flutter Error: The method ‘toInt‘ isn‘t defined for the class ‘Decimal‘

    1 运行项目报错 2 错误原因分析 从错误日志可以看出 是common utils插件中的decimal 2 0 0依赖库报错了 猜测可能是decimal升级版本了导致不兼容造成的 打开https pub flutter io cn 搜索d
  • Windows安装frida

    一 正常步骤 cmd中 pip3 install frida i https pypi mirrors ustc edu cn simple 上面失败用这个 pip install frida i http mirrors aliyun c
  • linux 查看及修改字符集

    一 查看当前linux系统的字符集方法 1 1 locale 1 2 echo LANG 1 3 env grep LANG 二 查看当前系统支持的字符集 root localhost locale a 三 修改系统字符集 3 1 临时生效
  • vue中使用bus总线在非父子组件之间传值

    使用bus总 线可以在 兄弟 父子 祖先和后代 组件之间传值 原理 在Vue原型中 创建一个bus属性 让每一个组件 实例 都具有这个属性 这里自行引入 vue
  • Idea 发布最适合程序员的字体!

    作为 编译期界的大佬 JetBrains公司一直致力于提供更好的编码环境 前两天 JetBrain推出了一个新的字体 JetBrain Mono 号称是最适合程序员的编码的字体 我赶紧尝了尝鲜 体验了一天之后发现确实好看 因此推荐给大家 首
  • ABB MPRC086444-005数字输入模块

    ABB MPRC086444 005 是一款数字输入模块 通常用于工业自动化和控制系统中 用于接收和处理数字信号 以下是这种类型的数字输入模块通常可能具备的一般功能和特点 数字输入接口 MPRC086444 005 模块通常配备多个数字输入
  • AttGAN从paper到code理解

    AttGAN Facial Attribute Editing by Only Changing What You Want 2017 CVPR 文章简介 本文研究面部属性编辑任务 其目的是通过操作单个或多个感兴趣的属性 如头发颜色 表情
  • RabbitMQ的安装和启动——windows版

    本章介绍如何在win10下安装 RabbitMQ 并启动 安装 Erlang 安装 RabbitMQ 启动 RabbitMQ 百度网盘下载 Erlang 和 RabbitMQ Erlang 网盘链接 RabbitMQ 网盘链接 结语 下载R
  • 搜索研发工程师需要掌握的一些技能

    文章目录 基础 语言 数据结构与算法 工程方面 搜索相关 搜索主要模块 电商搜索流程 分词相关 搜索召回 相似度算法 相关词推荐 排序相关 国美搜索 搜索算法工程师需要掌握的技能 基础 语言 大部分公司用的是Solr ElasticSear
  • 算法相关-经典排序算法(python实现)

    概述 插入排序 将未排序的元素同已排序的元素从后往前比较 带排序元素 a 被比较元素 b 如果a
  • 在Linux是使用libxml2---从安装到使用

    一 下载和安装LIBXML2 方法一 Libxml2是个C语言的XML程式库 能简单方便的提供对XML文件的各种操作 并且支持XPATH查询 及部分的支持XSLT转换等功能 Libxml2的下载地址是 http xmlsoft org 完全
  • 支撑区块链大规模商用,FISCO BCOS v3.0的那些“黑科技”

    注 文章转载自CSDN公众号 在2021年度金链盟生态大会上 全新的FISCO BCOS v3 0正式发布 该版本从架构 算法以及安全可控和隐私计算协同等方向进行了全面升级 满足数字经济时代对区块链系统可承载更大规模 更多场景 更广泛参与的
  • spring-xxx-xxx-0.0.1-SNAPSHOT.jar中没有主清单属性完美解决

    这种情况就是因为没有在SpringBoot中pom文件安装maven plugin 导致出现没有主清单属性问题 1 引入插件
  • JPush极光推送Unity插件iOS设备无法获取DeviceToken

    前言 最近在使用JPush进行极光推送 Unity插件GitHub地址https github com jpush jpush unity3d plugin 问题描述 但是发现了一个问题 按照官方文档操作 最终仍然无法获取DeviceTok
  • Error: unable to connect to node rabbit@localhost: nodedown

    刚安装上rabbimq 当我使用rabbitmqctl start app 启动rabbitmq的时候 出现了如下问题Error unable to connect to node rabbit localhost nodedown 然后我
  • vue-quill-editor复制粘贴问题

    需求是这样的 富文本可以具备粘贴文本的功能 但是不能粘贴图片到编辑框中 于是百度一下很快就有了解决方案 在data的文本编辑框配置中添加一个clipboard粘贴板 对其进行配置 方法中可以自觉将粘贴的图片转换为空的字符串 所以巧妙实现了此
  • 解决ubuntu打不开软件更新器和软件中心的问题

    打不开可能是软件源的问题 试试 sudo gedit etc apt sources list 然后把第三方软件源全部删除掉 重启软件更新器 如果能够启动 但有提示请检查网络连接的信息 那么点设置 在其它软件选项卡看情况取消勾选一些软件源
  • 解决报错:无法使用 JSX,除非提供了 “--jsx“ 标志。ts(17004)

    在 vue cli 5 0 6下创建项目 打开代码突然出现 无法使用 JSX 除非提供了 jsx 标志 之前都没问题 今天打开一看就报错了 网上说是 typescript的本地版本和你当前项目的版本不一致 请将本地的ts版本更新至项目需要的

随机推荐

  • 【BrokenPipeError: [Errno 32] Broken pipe】的解决方案

    BrokenPipeError Errno 32 Broken pipe 的解决方案 项目场景 问题描述 原因分析 解决方案 End 项目场景 调试 GitHub项目bddoia project Explainable Object ind
  • Docker一运行容器就退出:已解决

    Docker一运行容器就退出 已解决 文章目录 Docker一运行容器就退出 已解决 问题引入 解决方法 问题引入 想着挂载一个数据卷人挪活设置个端口号在外部访问一下 结果刚刚运行就停止了 如下图所示 就算是给它加上做一个死循环 持续输出
  • 函数防抖知识要点

    函数防抖 debounce JavaScript 中的函数大多数情况下都是由用户主动调用触发的 比如说点击 拖拽 改变浏览器尺寸 提交表单等 除非是函数本身的实现不合理 否则一般不会遇到跟性能相关的问题 但是在一些少数情况下 函数的触发不是
  • Ubuntu14.04终端配置:颜色、大小写不敏感、上键搜索字符串开头的历史命令、右键显示打开终端_ubuntu一站式配置教程(三)

    Ubuntu14 04终端配置 颜色 大小写不敏感 上键搜索字符串开头的历史命令 右键显示打开终端 ubuntu一站式配置教程 三 16单独列出来 文章目录 Ubuntu14 04终端配置 颜色 大小写不敏感 上键搜索字符串开头的历史命令
  • 判断是否是视频还是图片

    当发请求后拿到数据需要对数据进行处理 判断是视频就显示视频 图片显示图片
  • 3D游戏编程与设计作业4——使用skybox构建游戏场景

    步骤1 首先下载支持使用Fantacy Skybox FREE 的Unity版本 2021 3 步骤2 打开unity store 搜索Fantacy Skybox FREE 并进行下载 步骤3 下载成功后import对应的包到项目中 步骤
  • 多进程中fork

    linux下多进程 fork 这里只是简单实用fork 大家想了解具体 欢迎到我的gitee 给个star include
  • Android APK反编译教程

    目录 一 反编译工具 二 注意事项 三 apktool 1 1 官方链接 1 2 下载安装 1 3 使用 四 dex2jar 1 1 官方链接 1 2 下载安装 1 3 使用 五 jd gui 1 1 官方链接 1 2 下载安装 1 3 使
  • 百度广告联盟代码优化

    再分享一下我老师大神的人工智能教程吧 零基础 通俗易懂 风趣幽默 还带黄段子 希望你也加入到我们人工智能的队伍中来 https blog csdn net jiangjunshow
  • 关于Delphi的时间格式,图片处理的一些常用操作

    1 delphi 将字符串转换为时间 可以通过TFormatSettings 类来设置 FSetting ShortDateFormat yyyy MM dd FSetting DateSeparator DateTime1 StrToDa
  • vue若依前端项目搭建

    1 项目搭建 首先进入到你需要创建的项目目录下面 然后输入命令vue create 创建项目 接下来选择手动搭建 然后把下面图片中的内容选上 再然后继续配置一些参数信息 接下来运行npm run serve项目就启动起来了 2 配置登录界面
  • 【学习】若依源码(前后端分离版)之 “ 上传图片功能实现”

    大型纪录片 学习若依源码 前后端分离版 之 上传图片功能实现 前言 前端部分 后端部分 结语 前言 图片上传也基本是一个项目的必备功能了 所以今天和大家分享一下我最近在使用若依前后端分离版本时 如何实现图片上传功能的经验和心得 前端部分 在
  • 服务器硬件知识普及篇(需要配置服务器的朋友可以参考)

    开篇一 服务器主板 服务器主板概述 对于服务器而言 稳定性才是首要 服务器必须承担长年累月高负荷的工作要求 而且不能像台式机一样随意的重起 为了提高起可靠性普遍的做法都是部件的冗余技术 而这一切的支持都落在主板的肩上 下面我就来看看有关服务
  • JAVA word转pdf各个版本都支持,aspose-words

    以下提供两种方法实现 建议使用aspose 一 第一种 使用aspose words Word转PDF 第一步 首先需要下载aspose words 15 8 0包 官方的地址很慢 并且包下载不下来 有需要可以去GITHUB上寻找 这里我提
  • async/await处理多个异步请求

    async await 处理异步操作 axios defaults baseURL http localhost 9999 async function queryData let result await axios get adata
  • 使用MyEclipse创建JSP页面的一般步骤

    一 MyEclipse下建立点 当然事先JDK以及Tomcat以及装好 在包资源管理器中 新建Web Project 站点名称 MyJSP2 选择当前站点的工作目录 默认是我们打开MyEclipse时设置的工作目录 在这里也可以修改 最好是
  • 关于写死bootargs实例

    文章目录 1 说明 2 举例 3 原理 1 说明 1 附加的内核命令行 cmdline BOARD KERNEL CMDLINE 在build core Makefile中 有以下一段内容 strip起到去除空格的作用 BOARD KERN
  • 2020-03-12 git分支

    1 git c 配置 git c
  • mysql怎么生成ER_navicat怎么生成er

    Navicat软件真是一个好东西 今天需要分析一个数据库 然后想看看各个表之间的关系 所以需要查看表与表之间的关系图 专业术语叫做ER关系图 默认情况下 Navicat显示的界面是这样的 软件将表当做一个对象 然后显示了所有的表 仅仅通过这
  • 进程同步之信号量机制(pv操作)及三个经典同步问题

    1 信号量机制 信号量机制即利用pv操作来对信号量进行处理 什么是信号量 信号量 semaphore 的数据结构为一个值和一个指针 指针指向等待该信号量的下一个进程 信号量的值与相应资源的使用情况有关 当它的值大于0时 表示当前可用资源的数