用信號量進程同步與互斥


1.理解生產者和消費者問題

沒有引入信號量時的生產者和消費者進程,什么情況下會出現結果不唯一?什么情況下會出現永遠等待?

用信號解決生產者和消費者的同步與互斥,要求能自己寫出來。

答:sleep()和wakeup()是操作系統基本內核函數,他們被封裝在函數庫中供應用程序使用,執行sleep()時,讓調用進程進入等資源隊列,當資源可用時從相應隊列釋放等資源的進程。

結果不唯一:當進程之間共享變量counter,對counter的訪問未加限制,生產者進程和消費者進程對counter的交替操作會使其結果不唯一,例如counter的當前值為8,如果生產者生產一件產品並投入緩沖區,擬執行counter加1操縱,同時消費者獲取一個產品消費,擬執行counter減1操作,假如兩者交替執行加1或減1操作,取決於其執行速度,counter的值可能是9,也可能是7,但是其正確值應該是8.

出現永遠等待:假定消費者讀取counter值時發現它為0,此時調度程序暫停消費者進程,讓生產者進程運行,生產者加入一個產品,將counter的值加1,他想當然的推想由於counter值剛才為0,所以此時消費者一定是在睡眠,於是生產者調用wakeup()函數來喚醒消費者,遺憾的是,消費者尚未睡眠時喚醒信號丟失,當消費者下次運行時,因已測到counter的值為0,於是去睡眠,這樣生產者遲早會填滿緩沖區然后去睡眠,這樣就造成了所有進程都永遠處於睡眠狀態。

PV操作:

item B[k];

semaphore empty;empty=k;

semaphore full;full=0;

semaphore mutex;mutex=1;

int in=0;

int out=0;

cobegin

  process producer_i)(){

    while(ture){

      produce();

      P(empty);

      P(mutex);

      apppend to B[in];

      in=(in+1)%k;

      V(mutex);

      V(full);

}

process consumer_j(){

  while(ture){

    P(full);

    P(Mutex);

    take from B[out];

    out=(out+1)%k;

    V(muter);

    V(empty);

    consume();

  }

}

}

2.哲學家吃面問題

semaphore fore[5];
for (int i=0;i<5;i++)
{

  fork[i]=1;
}

cobegin

process philosopher_i(){

  while(ture){

    think();

    P(fork[i]);

    P(fork[(i+1)%5]);

      eat();

    V(fork[i]);

    V(fork[(i+1)%5]);

  }

}

coend

分析:顯然,最多兩個哲學家同時吃面,假如每個哲學家都拿起一只筷子,就會永久等待(死鎖),下面介紹一種方法。

typedef int Semaphore;       //定義信號量Semaphore類型是整型的別名
const int N = 5;             //定義哲學家的數目,該數目可以根據需要修改
const LEFT (i-1)%N;          //哲學家i的左鄰
const RIGHT (i+1)%N;         //哲學家i的右鄰
enum status{Thinking,Hungry,Eating};//哲學家所處的三種狀態的常量枚舉  
Semaphore mutex = 1;         //定義一個互斥信號量,實現對臨界區的互斥
semaphore s[N] = {0};        //每個哲學家對應的信號量,初值為0
int state[N];                //每個哲學家的狀態數組

  

void TakeChopstick(int i)    //第i個哲學家試圖拿筷子
{
    P(mutex);                //進入訪問共享變量state[i]的臨界區前對mutex的P操作 
    state[i]=Hungry;         //設置狀態為飢餓
    test(i);                 //測試能不能取筷子
    V(mutex);                //起開臨界區
    P(s[i]);                 //如果沒有筷子,進程阻塞
}

  

void PutChopstick(int i)     //哲學家i放下筷子
{ 
    P(mutex);                //訪問臨界區的互斥信號量
    State[i]=Thinking;       //吃完了,放下筷子進入思考狀態
    test(LEST);              //喚醒左邊哲學家拿筷子
    test(RIGHT);             //喚醒右邊哲學家拿筷子
    V(mutex);                //離開臨界區
}

  

void test(int i)
{
    if(state[i]==Hungry && state[LEFT] != Eating &&state[RIGHT] !=Eating)
    {
        State[i]=Eating;
        V(s[i]);        //喚醒哲學家進程,喚醒當前被阻塞的進程
    }
}

  

process Phliospher(int i)
{
    while(1)
    {
        思考;
        TakeChopstick(i);
         吃面條;
         PutChopstick(i);
    }
}

  3.讀寫文件問題

單純使用信號量不能解決此此問題,必須引入計數器readcount對讀進程計數,mutex是用於對計數器readcount操作的互斥信號量,writerblock表示是否允許寫的信號量。

int readcount=0;

semaphore writeblock,mutex;

writeblock=1;mutex=1;

cobegin

process reader_i(){        process writer_j(){

  P(mutex);            P(writeblock);

  readcount++;           V(writeblock);

  if(readcount==1)       }

    P(writeblock);

    V(mutex);

    P(mutex);

    readcount--;

    if(readcount==0)

      V(writeblock);

    V(mutex);

}

coend

 

4.理發師問題

int waiting =0;

int CHAIRS=N;

semaphore customers,barbers,mutex;

customers=0;barber=0;mutex=1;

cobegin

  process barbers(){

    while(ture){

      P(customers);

      P(mutex);

      waiting--;

      V(barber);

      V(mutex);

      cutair();

    }

}

process customer_i(){

  P(mutex);

  If(waiting<CHAIRS){

    waiting++;

    V(customers);

    V(mutex);

    P(barbers);

    get_haircut();

}

else

    V(mutex);

}

coend

第一隊音樂愛好者要競爭“待出售的音樂磁帶和電池”,而且在初始狀態下,系統並無“待出售的音樂磁帶和電池”,故可為該種資源設置一初值為0的信號量buy1,同樣,需設置初值為0的buy2、buy3分別對應“待出售的隨聲聽和電池”、"待出售的隨聲聽和音樂磁帶"。另外,為了同步買者的付費動作和給貨動作,還需設置信號量payment和goods,以保證買者在付費后才能得到所需商品,信號量music overi用來同步音樂愛好者聽樂曲和酒吧老板的下一次出售行為,具體如下:

semaphore buy1=buy2=buy3=0;

semaphore payment=0;

semaphore goods=0;

swmaphore music_over=0;

cobegin{

process boss(){//酒吧老板

while(ture){

拿出任意兩種物品出售;

if(出售的是音樂磁帶和電池) V (buy1);

else if(出售的是隨聲聽和電池) V(buy2);

else if(出售的是隨聲聽和音樂磁帶) V(buy3);

P(payment);//等待支付

V(goods);//給貨

P(music_over);//等待樂曲結束

}

}

process fan1(){//第1隊音樂愛好者

while(ture){//因為一個進程代表一隊,而不是一個愛好者,所以這里是//while(ture)

P(buy1);//等有音樂磁帶和電池出售

V(payment);//付費

P(goods);//取貨

欣賞一曲樂曲;

V(music_over);//通知老板樂曲結束

}

}

process fan2(){//第二隊音樂愛好者

while(ture){

P(buy2);  //等有隨聲聽和電池出售

V(payment);//付費

P(goods);//取貨

欣賞一曲樂曲;

V(music_over);//通知老板樂曲結束

}

}

process fan3(){//第三隊音樂愛好者

while(ture){

P(buy3);  //等有隨聲聽和音樂磁帶出售

V(payment);//付費

P(goods);//取貨

欣賞一曲樂曲;

V(music_over);//通知老板樂曲結束

}

}

coend

6.某銀行有人民幣儲蓄業務,由n個儲蓄員負責。每個顧客進入銀行后先取一個號,並且等着叫號。當一個儲蓄人員空閑下來,就叫下一個號。請用P,V操作正確編寫儲蓄人員和顧客進程的程序。

var customer_counter,mutex:semaphore;

    customer_counter:=0;

  mutex:=1;

cobegin

  process customer

    begin

      L1:take a number;

        P(mutex0);

          進入隊列;

        V(mutex);

        V(customer_count);

        go to L1;

    end

  Process serversi(i=1,2,3...)

    begin

      P(cunstom_count);

      P(mutex);

      從隊列區號;

      V(mutex);

      為該號客人服務;

      end;

coend;

8.九、在一個盒子里,混裝了相等數量的黑棋子和白棋子,現要用自動分揀系統把黑棋子和白棋子分開,該系統由兩個並發執行的進程P1和P2組成,其中進程P1專門揀黑子,進程P2專門揀白子。規定兩個進程輪流揀子且每個進程每次只揀一個子。當一個進程在揀子時不允許另一個進程去揀子,並設P1先揀。請用P,V操作管理這兩個並發進程,使其能正確實現上述功能

var S1,S2:semaphore;

S1:=1;S2:=0;

cobegin

{

process P1

begin

repeat

P(S1);

揀白子

V(S2);

until false;

end

process P2

begin

repeat

P(S2);

揀黑子

V(S1);

until false;

end

}

coend.


免責聲明!

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



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