操作系統——信號量例題


  有一個倉庫,可以存放 A 和 B 兩種產品,倉庫的存儲空間足夠大,但要求: (1)一次只能存入一種產品(A 或 B); (2)-N < (A 產品數量-B 產品數量) < M。 其中,N 和 M 是正整數。試用“存放 A”和“存放 B”以及 P、V 操作描述產品 A 與 產品 B 的入庫過程。

Semaphore Sa = M - 1;
Semaphore Sb = N - 1;
//代表還能存入的數量

Semaphore mutex = 1;

process_A() {
	while(1){
		P(Sa); //取一個A產品准備入庫
		P(mutex);
		A產品入庫;
		// A產品入庫后還能存入A產品數量-1
		V(mutex);
		V(Sb); //還能存入B產品數量+1
	}
}

process_B() {
	while(1){
		P(Sb); //取一個B產品准備入庫
		P(mutex);
		B產品入庫;
		// B產品入庫后還能存入B產品數量-1
		V(mutex);
		V(Sa); //還能存入A產品數量+1
	}
}

  桌子上有一只盤子,最多可容納兩個水果,每次只能放入或取出一個水果。爸爸專向盤子放蘋果( apple),媽媽專向盤子中放桔子( orange);兩個兒子專等吃盤子中的桔子,兩個女兒專等吃盤子中的蘋果。請用 P、 V 操作來實現爸爸、媽媽、兒子、女兒之間的同步與互斥關系。

Semaphore mutex = 1;      //互斥信號量, 其初值為1
Semaphore empty = 2;       //記錄允許向盤子中放入水果的個數,初值為2
Semaphore orange = 0;      //盤子中已放入的蘋果的個數,初值為0
Semaphore apple = 0;      //盤子中已放入的桔子的個數,初值為0
main()
{
Cobegin
{
   father                    //父親進程
    {
    while (true)
       {
           P(empty);           //減少盤中可放入的水果數
                P(mutex);           //申請向盤中取、放水果
                向盤中放蘋果;
                V(mutex);           //允許向盤中取、放水果
                V(apple);           //遞增盤中的蘋果數
        }
     }
    mother                    //母親進程
    {
    while (true)
       {
          P(empty);           //減少盤中可放入的水果數
                P(mutex);           //申請向盤中取、放水果
                向盤中放桔子;
                V(mutex);           //允許向盤中取、放水果
                V(orange);          //遞增盤中的桔子數
        }
    }
    daughteri(i=1,2)      //兩女兒進程
    {
    while (true)
       {
            P(apple);           //減少盤中蘋果數
                P(mutex);           //申請向盤中取、放水果
                取盤中蘋果;
                V(mutex);           //允許向盤中取、放水果
                V(empty);           //遞增盤中可放入的水果數
        }
     }
    sonj(j=1,2)           //兩兒子進程
    {
    while (true)
       {
          P(orange);          //減少盤中桔子數
                P(mutex);           //申請向盤中取、放水果
                取盤中桔子;
                V(mutex);           //允許向盤中取、放水果
                V(empty);           //遞增盤中可放入的水果數
        }
     }
   }
    Coend
}

  有一個理發師,一把理發椅和 N 把供等候理發的顧客坐的椅子。如果沒有顧客,則理發師便在理發師椅子上睡覺;當一個顧客到來時,必須喚醒理發師進行理發;如果理發師正在理發時又有顧客來到,則如果有空椅子可坐,他就坐下來等,如果沒有空椅子,他就離開。為理發師和顧客各編一段程序(偽代碼)描述他們的行為,要求不能帶有競爭條件。

Semaphore mutex = 1;    //互斥信號量,初值為1.
Semaphore  Wait = 0;     //等待服務的顧客數
Semaphore  barbers= 0;    //等待顧客的理發師數
Int custNum = 0;    //等待的顧客(還沒理發的)

Costumer()
{
  while(true)
  {
        P(mutex);            //申請理發
        if(custNum>0)
     {
            if(custNum<N)   //若等待人數小於N
       {
                V(mutex);     //釋放進程等待
                CustNum++;     //增加等待人數
            }
       else            //若等待人數超過N
        {
                V(mutex);   //釋放進程等待
                離開;
             }
     }
    else                //若目前無人等待
    {
            V(mutex);        //釋放進程等待
            V(barbers);     //如果必要的話,喚醒理發師
            理發;
            離開;
            P(mutex);        //要求進程等待
            custNum--;        //顧客人數減1
            V(mutex);       //釋放進程等待
            V(wait);        //等待人數減1
    }
  }
}

Barber()
{
  while(true)
  {
        P(mutex);            //要求進程等待
        if(custNum ==0)    //目前無顧客
     {
            V(mutex);        //釋放進程等待
            P(barbers);        //理發師睡覺
       }
    else
    {
            V(mutex);        //釋放進程等待
            理發;
    }
  }
}

  吸煙者問題。三個吸煙者在一間房間內,還有一個香煙供應者。為了制造並抽掉香煙,每個吸煙者需要三樣東西:煙草、紙和火柴。供應者有豐富的貨物提供。三個吸煙者中,第一個有自己的煙草,第二個有自己的紙,第三個有自己的火柴。供應者將兩樣東西放在桌子上,允許一個吸煙者進行對健康不利的吸煙。當吸煙者完成吸煙后喚醒供應者,供應者再放兩樣東西(隨機地)在桌面上,然后喚醒另一個吸煙者。試為吸煙者和供應者編寫程序解決問題。

Semaphore S = 1;                //供應者
Semaphore S1,S2,S3;                //三個吸煙者
S1 = S2 = S3 = 0;
bool flag1,flag2,fiag3;            //三種吸煙原料
fiag1=flag2=flag3=true;

Apply()                            //供應者
{
  While(true)
  {
          P(S);
        取兩樣香煙原料放桌上,由flagi標記;
        if (flag2 && flag3) //供紙和火柴
      {
           V(S1);          //喚醒吸煙者一
          }
         else if(flag1 && fiag3) //供煙草和火柴
      {
           V(S2);                //喚醒吸煙者二
          }
       else                      //供煙草和紙
      {
           V(S3);                //喚醒吸煙者三
           }
   }
}

Smoker1()                         //吸煙者一
{
   While(true)
   {
       P(S1);
       取原料;
       做香煙;
       V(S);                    //喚醒供應者
       吸香煙;
   }
}

smoker2()                        //吸煙者二
{
   While(true)
   {
       P(S2);
       取原料;
       做香煙;
       V(S);                    //喚醒供應者
       吸香煙;
   }
}

Smoker3()                        //吸煙者三
{
   While(true)
{
       P(S3);
       取原料;
       做香煙;
       V(S);                    //喚醒供應者
      吸香煙;
   }
}

   面包師問題。面包師有很多面包和蛋糕,由 n 個銷售人員銷售。每個顧客進店后先取一個號,並且等着叫號。當一個銷售人員空閑下來,就叫下一個號。請分別編寫銷售人員和顧客進程的程序。

Semaphore buyer= 0;                //顧客人數
Semaphore seller = n;            //銷售人員數
Semaphore mutex_s = 1;            //用於銷售人員的互斥信號量
Semaphore mutex_b = 1;            //用於顧客的互斥信號量
int count_s = 0;                //記錄取號的值
int count_b = 0;                //記錄叫號的值

void Buy()                    //顧客進程
{
    進店;
   P(mutex_b);          //取號
   count_b++;
   V(mutex_b);
   V(buyer);
  P(seller);            //等待叫號
   買面包;
   離開
}

void Sell()
{
   while(true)
   {
        P(buyer);
        P(mutex_s);   //叫號
        count_s++;
        叫編號為count_s的顧客;
        V(mutex_s);
        V(seller);
   }
}

   桌上有一空盤,運行存放一只水果,爸爸可向盤中放蘋果,也可放桔子,兒子專等吃盤中的桔子,女兒專等吃盤中的蘋果。規定當盤中空時一次只能放一個水果供吃者取用,用 P,V 原語實現爸爸兒子和女兒 3 個並發進程的同步。

	Semaphore S = 1;      //S 表示盤子是否為空;
Semaphore Sa = 0;        //Sa 表示盤中是否有蘋果;
Semaphore Sb = 0;    //Sb 表示盤中是否有桔子;

Father()            //父親進程
{
    while(TRUE)
  {
        P(S);
        將水果放入盤中;
        if (放入的是桔子)
            V(Sb);
        else
            V(Sa);
    }
}

Son()                  //兒子進程
{
    while(TRUE)
  {
        P(Sb);
        從盤中取出桔子;
        V(S);
      吃桔子;
    }
}

Daughter()            //女兒進程
{
    while(TRUE)
  {
        P(Sa);
        從盤中取出蘋果;
        V(S);
        吃蘋果;
    }
}

   寫者優先的讀者--寫者問題。讀者-寫者問題為數據庫訪問建立了一個模型。例如,一個系統,其中有許多競爭的進程試圖讀寫其中的數據,多個進程同時讀是可以接受的,但如果一個進程正在更新數據庫,則所有的其他進程都不能訪問數據庫,即使讀操作也不行。寫者優先是指當一個寫者到達時,將阻止其后面的讀者進入數據庫,直到其離開為止。

	Semaphore Mut1, Mut2, Wmutex, Fmutex;          //互斥信號量
int Rcount, Wcount;                          //讀寫者人數
Mut1 = Mut2 = WMutex = Fmutex = 1;
Rcount = Wcount = 0;

Writer()                            //寫者進程
{
   While(true)
   {
       P(Mut1);
       Wcount=Wcount+1;
       If (Wcount==1)
     {
           P(Fmutex);     //如有讀者,寫者阻塞在此處
       }
       V(Mut1);
       P(WMutex);
       寫;
       V(Wmutex);
       P(Mut1);
       Wcount=Wcount-1;
       If (Wcount==0)
      {
           V(Fmutex);
       }
       V(Mut1);
   }
}

Reader()                            //讀者進程
{
   While(true)
   {
       P(Mut2);
       Rcount=Rcount+1;
       If (Rcount==1)
      {
           P(Fmutex);
       }
       V(Mut2);
       讀;
       P(Mut2);
       Rcount=Rcount-1;
       If (Rcount==0)
      {
            V(Fmutex);
       }
       V(Mut2);
   }
}

   在天津大學與南開大學之間有一條彎曲的小路,這條路上每次每個方向上只允許一輛自行車通過。但其中有一個小的安全島 M,同時允許兩輛自行車停留,可供兩輛自行車已從兩端進入小路的情況下錯車使用。如圖所示。
file
下面的算法可以使來往的自行車均可順利通過。其中使用了 4 個信號量, T 代表天大路口資源, S 代表南開路口資源, L 代表從天大到安全島一段路的資源, K 代表從南開到安全島一段路的資源。程序如下,請在空白位置處填寫適當的 PV 操作語句,每處空白可能包含若干個 PV 操作語句。

begin
    t:=1;s:=1;l:=1;k:=1;
    cobegin
    從天大到南開的進程
        begin
            ______(1)______
           通過 L 路段;
           進入安全島 M;
           ______(2)______
           通過 K 路段
           ______(3)______
        end
   從南開到天大的進程
       begin
          略,與“從天大到南開的進程”相反。
       end
    coend
end

  解答:

  (1) P(t); P(l);

  (2) V(l); P(k);

  (3) V(k); V(t);

  三個進程 P1、 P2、 P3 互斥使用一個包含 N(N>0)個單元的緩沖區。 P1 每次用 produce()生成一個正整數並用 put()送入緩沖區某一空單元中;P2 每次用 getodd()從該緩沖區中取出一個奇數並用 countodd()統計奇數個數;P3 每次用 geteven()從該緩沖區中取出一個偶數並用 counteven()統計偶數個數。請用信號量機制實現這三個進程的同步與互斥活動,並說明所定義信號量的含義。要求用偽代碼描述。

P1()
{
   While(true)
   {
       X = produce();      //生成一個數
      P(empty);     //是否有空單元格
       P(mutex);    //進入臨界區
       Put();
       if(X%2 == 0)
            V(s2);   //如果是偶數,向P3發出信號
       else
             V(s1);   //如果是奇數,向P2發出信號
       V(mutex);         //離開臨界區,釋放互斥信號量
   }
}

P2()
{
   While(true)
   {
       P(s1);     //收到P1發送來的信號,已產生奇數
      P(mutex);         //進入臨界區
       getodd();
       countodd():=countodd()+1;
       V(mutex);
       V(empty);         //離開臨界區,釋放互斥信號量
   }
}

P3()
{
   While(true)
   {
      P(s2)        //收到P1發送來的信號,已產生偶數
      P(mutex);         //進入臨界區
      geteven();
      counteven():=counteven()+1;
      V(mutex);
      V(empty);         //離開臨界區,釋放互斥信號量
   }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM