1. 程式人生 > >作業系統程序同步三大問題:生產者消費者,哲學家進餐,讀者寫者問題

作業系統程序同步三大問題:生產者消費者,哲學家進餐,讀者寫者問題

對於非科班出身的我,,,最近自學作業系統做了一些程序同步的筆記,寫出來,希望能對大家有幫助,我是參照哈工大張英濤老師的視訊和湯子瀛的書寫的:

程序與程序之間的合作機制

訊號量機制!!!

訊號量是一種資料結構。

訊號量的值與相應資源的使用情況有關。

訊號量的值僅由原語P、V操作改變

(1)整型訊號量

整型數  S <=0 代表資源被佔用,不可用   S>0代表空閒可用

P操作(wait)原語

V操作(signal)原語

Wait(S)

  While S<=0 do no-op(無行為)

       S:=S-1;  //可用啦,那我就用咯

Signal(S)

  S:=S+1;

wait(S) 和signal(S)是原子操作。

缺點:只要訊號量小於等於0,不滿足讓權等待。就是不會先讓其進入阻塞,把CPU讓給別人用。

(2)記錄型訊號量(目前應用較廣)

記錄型結構,包含兩個資料項:

Type semaphore  = record

                Value:integer;

                L:lise of process;

                end

S.value為資源訊號量初值,是某類資源的數目;

value大於0 的時候代表可用資源數目

value<0時候,絕對值代表等待使用資源的程序個數。也就是扔進阻塞佇列。

wait操作申請某一個單位資源

Procedure wait(s)

Var S:semaphore;  

Begin

  S.value:=S.value-1;

  If S.value<0 then block(s,L);

End

signal操作:釋放一個資源

Procedure signal(s)

Var S:semaphore;

Begin

  S.value = S.value+1;

  If S.value<=0 then wakeup(s,L)   //這裡小於0的話,說明還有程序在等待。

end

當S.value=1則是訪問臨界資源,是互斥訊號量。

死鎖現象:

   Pa                 pb

   ……               ……

wait(Dmutex)         wait(Emutex)

wait(Emutex)         wait(Dmutex)

   ……               ……

(3)AND型訊號量

基本思想:將所需的資源一次性全部獲取,使用後一次性全部釋放。

Swait(s1,s2,..,sn)

If s1>=1 and ... and sn>=1 then

  For i:=1 to n  do

     Si:= si-1;

  End for

Else

當發現第一個Si<1就把該程序放入阻塞等待佇列,並將其程式計數器至於Swait操作的開始位置(也就是把下一條指令改下。)

End if

Ssignal(s1,s2,..,s3)

For i:1 to n do

  Si := si +1;

將所有等待si的程序由等待佇列取出放到就緒佇列

End for

用訊號量能實現互斥:兩個程序程式碼見下面

Var mutex:semaphore:=1;

Begin

  Parbegin  //從部分開始的程式碼

  Process1:begin

    Repeat

      Wait(mutex);   // P操作 訊號量mutex

      Critical section

      Signal(mutex)

      Remainder section

   Until false;

  End

  Process2:begin

    Repeat

      Wait(mutex);

      Critical section

      Signal(mutex);

      Reminder section

    Until false;

  end

注意點:

wait(mutex) 和 signal(mutex) 必須成對出現。

經典的同步問題!!!!!!!!!!!!!!!

1、生產者-消費者問題

2、讀者-寫者問題

3、哲學家進餐問題

生產者-消費者問題

一組生產者程序生產產品給一組消費者消費。為使他們併發執行,設有一個n個緩衝區的緩衝池,生產者一次向一個緩衝區投入訊息,消費者從一個緩衝區中取得訊息。這是兩個程序相互合作的模型。!

制約關係:

(1)不允許消費者到一個空緩衝區中取資料

(2)不允許生產者向一個已滿的緩衝區投入資料。

例如:輸入時,輸入程序是生產者,計算程序是消費者

     輸出時,計算程序是生產者,列印程序是消費者

這裡用記錄型訊號量來解決生產者-消費者問題。區分下互斥量和訊號量

(什麼是記錄型?用一個數據結構來表示,整型表示使用資源和等待程序數,隊列表示阻塞佇列)

(1)設有n個緩衝區,每個緩衝區存放一個訊息,用互斥量mutex對緩衝池實現互斥訪問。

所以這裡第一個訊號量是用來作為互斥用的,初值是1;;;;這是使得投入和取出這兩個動作時互斥的,不能同時進行。!!!!

(2)用資源訊號量empty和full分別表示緩衝池中空緩衝區及滿緩衝區的數量。所以這裡資源訊號量是用來同步用的,empty初值是n,full初值是0。

Var mutex:semapjore:=1;

   Empty:semphore:=n;

   Full:semaphore:=0;

Buffer:array[0,...,n-1] of item; // 這裡用陣列形式,可以指明下一個資料存放位置用迴環就好

In,out:integer:=0,0;  //放入和取出的資料地址,就是陣列的兩個下表指向。

Procedure:begin

  Repeat

  ……

  Procedure an item nextp;  // 生產下一個產品,就是產生一個數據

  ……

    Wait(empty);  // 申請成功則empty減一了唄

    Wait(mutex);

    Buffer(in):=nextp;

    In:=(in+1) mod n;

    Signal(mutex);

    Signal(full);

  Until false;

  End

Consumer:begin

  Repeat

    Wait(full)

    Wait(mutex)

    Nextc := buffer(out);

    Out :=(out+1) mod n;

    Signal(mutex);

    Signal(empty);

  Consumer the item in nextc;  //對應的,也有一個消費過程

  Until false;

  End;

注意點:

1:wait(mutex)和signal(mutex)必須成對出現。不過這裡訊號量的出現不是在同一個程序當中就是了。

2:這裡mutex和empty full必須用mutex的型別變數把。不然也會出現同步問題。

3:這裡P操作是不能顛倒的,否則會進入死鎖,比如生產者應該先獲取empty,因為在消費者那裡也會對empty進行操作,。。所以一定要先鎖定互斥量,再進行訊號量,V操作倒是沒有順序要求。

2、哲學家進餐問題

有五個哲學家,他們的生活方式是交替進行思考和進餐。 哲學家們共用一個圓桌,有五張椅子,五個碗,五隻筷子,所以一個科學家想吃飯應該同時拿起最近的左右筷子吃。所以要協調他們吃飯時間。

分析:筷子就是臨界資源!在一段時間內只能有一個科學家使用。用一個訊號量表示一個筷子,五個筷子就共有五個訊號量,

var chopstick: array[0...4] of semaphore

每個訊號量初始化為1;

用記錄型訊號量來解決

設第i個哲學家

Repeat

  Wait(chopstick[i]);

  Wait(chopstick[(i+1)mod 5]);   // 由於這五個筷子是同個地位的,所以取哪個先都可以

  Eat...

  Signal(chopstick[i]);

  Signal(chopstick[(i+1)mod 5]);

  Think;

  Until false;

end

但是,當五個哲學家同時飢餓,那麼五個人同時拿起左邊筷子,那麼五個人就無限等待下去了。。。這就死鎖了。

解決辦法:

(1)至多四個人拿起左邊筷子。。保證至少有一個人可以用餐,那麼就能解決了。

(2)僅當左右兩個筷子同時拿起才能進餐  類似AND型訊號量

(3)規定奇數號的先拿起左邊的,偶數號拿右邊。。

用AND型訊號量來解決哲學家問題:同一組人使用同一些東西。

var chopstick:array[0...4] ofsemaphore:={1,1,1,1,1};

Repeat

  Think;

  Swait( Chopstick[i] and chopstick[(i+1)mod 5]);

  Eat;

  Ssignal(Chopstick[i] and chopstick[(i+1)mod 5]);

  Think;

  Until false;

end

(3)讀者-寫者問題

一個數據檔案或記錄可被多個程序共享,其中,有些程序要求讀,有些程序則要求寫或修改。

把只要求讀的程序 Reader程序 要求寫修改的是Writer程序。

允許多個讀者程序同時共享一個物件,不允許一個writer程序和多個Reader程序或Writer程序同時訪問共享物件。

這裡的共享物件不是臨界資源,因為允許多個程序訪問---讀!

(1)為解決一個writer程序和reader程序互斥,設定一個互斥訊號量Wmutex;

(2)設定一個整型變數Reader count表示正在讀的程序數目。

(3)ReaderCount是可以被多個程序訪問的臨界資源,為它設定互斥訊號量Rmutex;

(4)僅當Readercount = 0,表示無reader程序在讀,Reader程序執行P操作。若P操作成功,Reader程序便可讀,使得Readercount+1;其他Readercount的值就不需要P操作了。

記住Rmutex是為了保證多個執行緒訪問Readercount個數同步問題才建立的!!

Var Rmutex,Wmutex:semaphore:= 1,1;

  Readercount:integer:=0;

  Begin

  Parbegin

    Reader:begin

      Repeat

      Wait(Rmutex);

      If (Readercount=0 then Wait(Wmutex));

        Readercount++;

      Signal(Rmutex);

      Perform read operation;

      Wait(Rmutex);

    Readercount:=Readercount-1;

    If Readercount==0 then signal(Wmutex);

    Signal(Rmutex);

    Until false;

    End

    Writer:begin

    Repeat

    Wait(Wmutex);

    Perform write operation;

    Signal(Wmutex);

    Until false;

    End

  Parend

end