Download as pdf or txt
Download as pdf or txt
You are on page 1of 24

Ch6 Process Sychronization

Process Communication 兩大方式



1 Shared Memory


2 Message Passing

Shared Memory Message Passing


Def Process 透過對共享變數的存取,達到 透過 Commuication Link 溝通
彼此溝通的目的 Process 要溝通,雙方須:
(1) 建立 Communication Link
(2) Message 互相傳輸
(3) Release Commuication Link
傳輸量 大量訊息溝通 少量訊息傳輸
Speed 快 慢
Kernel No Yes
支持
Programmer Yes No
責任/負擔 須提供 Shared Variable 的互斥存取
機制
,以確保 Data 正確性
O.S Little…(or No) Yes
責任/負擔 只提供 Shared Memory Space 而已 e.g. C.link 的管理

Race Condition Problem


Def : 在 Shared Memory 溝通方式下,如果沒有給 Shared Variables 提供互斥存取機制,則
Shared Variable 的結果值會因為 Process 之間的交錯執行順序不同而不一樣,此一
Data inconsistency error 稱之。

解決 Race Condition 兩大策略



1 Disable Interrupt / Disable CPU (對 CPU)

2 Critical Section Design (對 Shared Variable)
Disable Interrupt
(一) 定義:Procee 在對共享變數進行存取前,先 Disable Interrupt,等到 Process 完成存取
後,才能 Enable Interrupt,如此一來,可保障 Process 對共享變數存取期間,
CPU 不被其他 Process preempted,確保是
atomically execution (不可分割執行),便可防 Race Condition
(二) 優點:適合用在 Uniprocessor (單一 CPU) system,簡單,易於實施
(三) 缺點:○
1 不適合用在 Multiprocessor system

原因:若只有 Disable Process 執行的那一個 CPU 之 Interrupt 是不夠的,無法防


止 Race Condition,因為從其他 CPUs 裡的 Process 仍可以存取共享變數。
所以,必須 Disable 全部的 CPUs 之 Interrupt,才可以防止 Race
Condition,但是 Performance 很差
(e.g.因為無法平行運算,大量訊息充斥)。

2 風險高:如果 Process Disable Interrupt 後不執行 Enable Interrupt,那

CPU 可能會被長期霸占而不能 Release。

Critical (Spinlock) Section Design


(一) Critical Section : Process 中對於共享變數進行存取的 code 片段,其他非 Critical
Section 區域,稱為 Remainder Section。
(二) Critical Section Design : 設計 Critical Section 前的 Entry Section 及後的
Exit Section 的 code 以確保 Race Condition 不會發生。

(三) 在 Entry Section 中用什麼卡住 Prcoess?


[法一] Busy waiting (Spinlock):透過 looping 敘述卡住 Process
• 優點:若 Process 只會卡在 loop 很短時間就離開 loop (比 context switch 短),則
Spinlock
• 缺點:等待中的 Process 仍與其他 Processes 競爭 CPU,將搶到的 CPU time 用於毫無進展的
loop 上,對 Performance 沒幫助。
☆若 Process 必須卡在 loop 很久,這是一個傷害
[法二]用 Block(P)、Wakeup(P) system call 來協助 Programmer
• Block(P):P 的狀態 Running → Blocked
• Wakeup(P):P 的狀態 Blocked → Ready
• 缺點:會有 Context Switching 之 Overhead
正確的 Critical Section Design 應滿足的 3 個 Criteria

1 Mutual exclusion:任一時間點,只允許 1 個 process 進入自己的 C.S 內活動,不可以有多

個 process 同時在他們的 C.S 內活動



2 Progress:必須同時符合下面 2 個條件

(1)不想進 C.S 的 process (or 在 R.S 的 process)不可以阻礙其他 process 進入


C.S (or 不參與進入 C.S 的決策)
(2)必須在有限時間內從想進入 C.S 之 process 中,挑選 1 個進入 C.S,即不可以永
遠無法決定誰可以進入 C.S,即不可大家皆無法進入 C.S (隱含 No Deadlock)
☆ Tips:有空位時讓「想進的人」「馬上」進入

3 Bounded waiting:自 process 提出進入 C.S 的申請到獲准進入 C.S 的等待時間是有限的,即

若有 n 個 process 想進入 C.S,則任一 process 至多等待 n-1 次即可進入


(隱含 No Starvation)

Critical Section – Software Solutions


(1) Failed algo 1 : Only Turn
1 2 個 process {(2) Failed algo 2 :Only Flag

(3) Successful algo 3:Peterson' s solution

2 n 個 process:Bakery’s algo (恐龍本已移除,請直接看洪逸筆記)

宣告共享變數 :

turn:整數,存放的値為 i 或 j,誰擁有此值誰就有資格進入。
flag[i]:布林陣列,表示 i 想不想進去。

1. Failed Algo 1 : Only Turn


違反 Progress (違反條件 1):假設目前 turn 值為 i,
repeat
但 Pi 不想進入 critical section。若此時 Pj 想進
while(turn!=i)do no-op
C.S
C.S.
Pj 卻無法進入被 Pi 阻礙,因為只有 Pi 才有資格將
turn = j;
turn 值改為 j (想進入無法馬上進入)。
R.S.
until False

2. Failed Algo 2 : Only Flag


違反 Progress (違反條件 2):如 Pi,Pj 依下列順序執
repeat
行,則 Pi,Pj 皆無法進入 C.S 形成 Deadlock
。
flag[i] = True
while( flag[j] ) do no-op;
flag[i] = True;
C.S.
flag[j] = True;
flag[i] = False
while( flag[j] );
R.S.
while( flag[i] ); // 太有禮貌,大家都想進都進不了
until False
3. Peterson’s solution
☆ Flag & turn 一起對稱修改也正確
repeat
flag[i] = True;
turn = j; //禮讓的概念
while ( flag[j] && turn == j); //想進去且輪到他進去
C.S.
flag[i] = False;
R.S.
until False

(1) Mutual exclusion


若 Pi 與 Pj 皆想進入自已的 C.S.,代表 flag[i] = flag[j] = true,而且會分別執行到
turn = i 及 turn = j 之設定,只是先後次序不同,turn 的值僅會是 i 或 j,絶不會兩者皆
是。
(2) Progressive
(i) 若 Pi 不想進入 C.S.,則表示 flag[i] = false。此時若 Pj 想進入自已的 C.S.,必可
通過 while(flag[i] and turn = i) do no-op 這個空迴圈而進入其 C.S.,不會
被 Pi 阻礙。
(ii) 若 Pi 與 Pj 皆想進入自已的 C.S.,則在有限的時間內,Pi 與 Pj 會分別執行到
turn = i 及 turn = j 之設定(只是先後次序不同),turn 値必為 i 或是 j。因
此 Pi (或 Pj)會在有限的時間內進入自已的 C.S. (No Deadlock)。
(3) Bounded-waiting
Pi 離開 C.S.後又企圖立刻進入自已的 C.S.,此時 Pi 一定會執行 turn = j,使得 Pi 無法
再搶先於 Pj 進入自已的 C.S.。所以 Pj 至多等待一次即可進入 C.S.。

Hardware Instruction Support


即 CPU 有提供下列指令之一,可以利用這些指令完成 C.S Design
simple algo 1

1 Test – and – Set {
正確版 algo 2

2 Swap

Test – and – Set


傳回參數值,將參數值設為 true,並保證是 atomically exection
Share variables :
Lock : boolean = False (初值)
waiting[i] : boolean = False (初值)
True:表 Pi 正在等待進入 C.S
意義:waiting[i] { 初值
False: {
Pi 已在 C.S 中,不用等
1. Simple algo 1
☆ 先搶到 Test_and_Set(Lock)指令,先進
repeat
C.S
while(Test_and_Set(Lock)) do no-op; //entry
違反 Bounded waiting:未規範 order 使得
C.S.
次序以亂數決定。
Lock = False; //exit
R.S.
until false

e.g. Pi 已先於 Pj 進入 C.S 且 Pj 在等待中,若 Pi 離開 C.S 後又想立刻進入 C.S,Pi 可能再度先


於 Pj 搶到 Test_and_Set(Lock)執行,於是在先於 Pj 進入 C.S ( Pj 可能 Starvation)。

2. 正確版 algo 2

Repeat
waiting[i] = true; //有意進 C.S,等待中
key = true;
while(waiting[i] && key) do //key = false,離開 while
//waiting 被別人改成 false,離開 while
key = Test_and_Set(Lock);
waiting[i] = false; //可以進入,不用等了 (拿掉會 Deadlock) 違反 Progress(i)(ii)
C.S.
j = (i+1) % n; //j 先從 i 的下一個 process 開始
while(j!=i && not waiting[j]) do //找下一個想進 C.S 的 Pj
j = (j+1) % n;
if(j == i) then Lock = False; //若成立,表示現在沒人想進 C.S
else waiting[j] = false; //讓 Pj 進入 C.S
R.S.
until false

(1) Mutual exclusion


Pi 可以離開 while(waiting[i] && key)而進入 C.S 之條件有 2 種 Case
Case 1 : key 為 false
代表 Pi 是所有 Process 中第一個搶到 Test_and_Set(Lock)執行之 Process 而得以進入
C.S,其餘 Process 之 key 皆為 true (唯一性成立)。
Caes 2 : waiting[i] = false
Pi 在未離開 while(waiting[i] && key),是無法改變自己的 waiting[i]為 false,只
有從 C.S 離開的 Process 才有資格改變別人的 waiting 值為 false,且只改 1 個
Process,加上從 C.S 離開的 Process 也只有 1 個 (唯一性成立)。
(2) Progressive
(i) 若 Pi 不想進入 C.S. (or 在 R.S 中)其 waiting[i] = false,代表 Pi 不會去搶
Test_and_Set(Lock)執行且從 C.S 離開的 Process 也不會去改它 waiting[i]值
(Pi 不會參與進入 C.S 的決策)。
(ii) 若多個 Processes 想進入 C.S,則在有限的時間內必有 1 個 Process 先執行
Test_and_Set(Lock)而進入 C.S (No Deadlock)。
(3) Bounded-waiting
假設 n 個 Processes Po~Pn-1 皆想進入 C.S (即 waiting[0]~waiting[n-1]皆為 true)
令 Po 是第 1 個進入 C.S 的 Process,此時 Lock 值改為 true,當 Po 離開後,將 waiting[1]
設 false,讓 P1 進入 C.S,而 P1 離開後,會將 waiting[2]設為 false,P2~Pn-1 以此類
推,Process 會依 Po,P1,P2…Pn-1 之 FIFO order 進入 C.S (No Starvation)。

Swap
Repeat
違反 Bounded waiting:未規範 order 使得次序以亂數決定。
key = true;
repeat
☆ 修改方法:將 Test-and-Set 中修改 1 行
SWAP(Lock, key);
until key = False;
while(waiting[i] && key) do
C.S.
key = Test_and_Set(Lock);
Lock = False;
Swap(key,Lock)
R.S.
Until false
Semaphore

1 wait(S) = P(S):while(S <= 0)do no-op; //S 大於 0 就給過,但 S 要減 1
S = S – 1;

2 Signal(S) = V(S):S = S + 1;

著名同步問題
1. Producer-Consumer Problem
N 個 buffers,Producer 製造項目,Consumer 消耗項目。
(i) 不完善的實現
宣告共享變數:

int itemCount = 0;

procedure producer() { procedure consumer() {


while (true) { while (true) {
item = produceItem(); if (itemCount == 0) {
if (itemCount == BUFFER_SIZE) { sleep();
sleep(); }
} item = removeItemFromBuffer();
putItemIntoBuffer(item); itemCount = itemCount - 1;
itemCount = itemCount + 1; if (itemCount == BUFFER_SIZE - 1) {
if (itemCount == 1) { wakeup(producer);
wakeup(consumer); }
} consumeItem(item);
} }
} }

☆ 雖然正確,但會有 Race Condition,進而引發 Deadlock


(ii) 用 Semaphore 解決
宣告共享變數:
semaphore mutex = 1 //對 Buffer 存取提供互斥機制,防止 Race Condition
semaphore fullCount = 0 //塞入 Data 數
semaphore emptyCount = BUFFER_SIZE

procedure producer() { procedure consumer() {


while (true) { while (true) {
item = produceItem(); wait(fullCount);
wait(emptyCount); //若 Buffer 滿,要等 wait(mutex);
wait(mutex); //通過互斥存取 item = removeItemFromBuffer();
putItemIntoBuffer(item); signal(mutex);
signal(mutex); //解除互斥 signal(emptyCount);
signal(fullCount); //塞入 Data 數 + 1 consumeItem(item);
} }
} }
2. Reader/Writer Problems
Allow multiple readers to read at the same time. Only one single writer can
access the shared data at the same time.

(1) R/W 互斥
(一)必須滿足的基本同步條件 { (RR 不需互斥)
(2) W/W 互斥

(二)可分 2 種

(1)First Reader/Writer Problem:對 Reader 有利,Writer 不利(Writer 可能飢餓)


{
(2)Second Reader/Writer Problem:對 Reader 不利,Writer 有利

(i) First Reader/Writer Problem


宣告共享變數:

int readcount = 0 //reader 個數


Semaphore mutex = 1 (in order to protect readcount)
//防止 readcount 有 Race Condition
Semahore wrt = 1 //提供 r/w,w/w 之基本互斥控制,同時兼作對 writer 不利之控制

do{//writer do{//Reader
wait(wrt); wait(mutex); 若成立代表你是第 1 個 reader
// writing is performed readcount++;
signal(wrt); if(readercount == 1) wait(wrt); //看是否可以通過 r/w 互斥,
}while(true); signal(mutex) 若可通過,也順便卡住 writer
// reading is performed
wait(mutex);
readcount--;
if(readcount == 0) signal(wrt); //沒有 reader,可放 writer
signal(mutex);
}while(true)

• reader 一直來 writer 會 starvation. (眾 reader 相當於是一個很愛佔位的 writer)


• No readers will wait until the writer locked the shared object.
• Readers need not to sync with each other.
(ii) Second Reader/Writer Problem
宣告共享變數:

Semaphore x = 1
Semaphore y = 1
Semaphore z = 1 //reader 入口區管制
Semaphore wsem = 1 //作 R/W、W/W 基本互斥控制 理論上可拿掉,是為了將第 1 個 reader 以外的
Semaphore rsem = 1 //作對 reader 不利之控制 reader 卡遠一點,讓 writer 全數做完後,讓
int readcount = 0 第 1 個 reader 搶先進去,且 writer 比
int writecount = 0 reader 稍微容易進入

Writer() Reader()
wait(y); wait(z);
writecount++; wait(rsem); //看可否通過對 reader 不利的控制
if(writecount == 1) wait(x);
wait(rsem); //築起對 reader 不利的控制 readcount++;
signal(y); if(readcount == 1)
wait(wsem); //通過 W/W 互斥 wait(wsem); //R/W 互斥
執行 writing signal(x);
wait(y); signal(rsem);
可 writecount--; signal(z);

到 if(writecount == 0) //No writer 執行 reading
signal(rsem); //解除對 reader 互斥 wait(x);
signal(wsem); //解除 W/W 互斥 readcount--;
signal(y); if(readcount == 0)
signal(wsem);
signal(x);
3. The Sleeping Barber Problem
(一)兩種 process :
• 理髮師(Barber)

沒有客人:被迫 wait
{
有客人:叫客人來剪髮,if 客人坐在 waiting chair

• 客人(Customer)

沒有 waiting chair:不進店裡
{ 理髮師 Busy:被迫 wait
有 waiting chair:進來坐下 {
理髮師 idle:叫醒 Barber

(二) Shared variables :


• Semaphore CustReady = 0 //有無等待的 customer,用以卡住 Barber,if no 客人
• Semaphore BarberReady = 0 // barber 是否準備就緒,用以卡住 Customer,if Barber
Busy
• Semaphore mutex = 1 // waiting chairs 是否可以作增減
• int waiting = 0 //作在 waiting chairs 上的客人數目

Barber Customer (沒有 repeat until)

repeat wait(mutex) //在 if 前就要 wait


while true: if (waiting < n){ //共享變數 read
wait(CustReady) waiting += 1
wait(mutex) signal(CustReady) //通知 Barber
waiting -= 1 signal(mutex)
signal(BarberReady) wait(BarberReady) //等 Barber,if busy now
signal(mutex) # (Have hair cut here.)
# (Cut hair here.) }
until False; else //不入店
signal(mutex)
4. The Dinning Philosophers Problem
把筷子當 Shared Resource,相鄰兩 Process 不可同時執行 C.S
(一)每個哲學家有 3 種狀態:
• thinking:不想吃飯,思考中 (R.S)。
• hungry:餓了,想吃飯 (C.S)。
• eating:同時取得左右筷子,可吃飯。
(二) 宣告共享變數:

chopstick[0...4] of semaphore,初值皆為 1 //每根筷子用 Semophore 作互斥控制


repeat 錯誤版本!此程
wait(chopstick[i]); 式並不正確,會有 Dead Lock 問題 (循環取得左邊筷
wait(chopstick[i+1] mod 5); 子,形成 circular waiting)。
//eating
signal(chopstick[i]);
signal(chopstick[i+1] mod 5);
until False;

(三)解法
[法一]最多只允許 4 位哲學家上桌
⇒ 保證 Deadlock free
[法二]規定除非哲學家可同時取得左右兩根筷子,才准許持有,否則不得持有任何筷子
⇒ 打破 Hold & Wait

奇數號哲學家先拿左再拿右
[法三]規定 {
偶數號哲學家先拿右再拿左

⇒ 打破 Circular Waiting
[補充] 6 位(偶數)哲學家 -> 用刀叉
(法一) 大家先取得左邊(刀 or 叉),再取右邊(刀 or 叉)
⇒ 可能 Deadlock
(法二) 規定:大家先取刀,再取叉
⇒ Asymmetric ordering 取資源
⇒ 打破 Circular waiting
Semaphore 的種類
[區分角度一]由號誌值的值域做區分
○1 Binary Semaphore

○2 Counting Semaphore -> 要用 2 個 Semaphore Implement

1. Binary Semaphore
定義:號誌值只會為 0 或 1,不可為負數,不知有多少 Processes 卡在 wait 中
2. Counting Semaphore
定義:號誌值可以是負值,不限於 0 或 1,且若值為 -N,可知有 N 個 Processes 卡在 wait 中
◎ 用 Binary Semaphore 定出 Counting Semophore
宣告共享變數:

int value (號誌值) //實作 Counting Semaphore (wait(value))


binary Semaphore s1 = 1 //對 value 做互斥,防止 Race Condition
binary Semaphore s2 = 0 //強迫 Processes 卡住,if value < 0

wait(value) signal(value)
wait(s1); wait(s1);
value = value – 1; value = value + 1;
if(value < 0){ if(value <= 0)//代表先前有 process 卡住
signal(s1); //先解 s1 互斥 signal(s2);
wait(s2); //在卡住自己 signal(s1); 前 value++,所以有等號
} //如果上面相反會 Deadlock
else
signal(s1);
[區分角度二]有無使用 Busy-waiting skill?
○1 有:也叫 Spinlock Semaphore


2 沒有:Non-Busy waiting Semaphore

1. Spinlock Semaphore
定義:Semaphore in wait operation 有使用 Busy-waiting skill 來使 process wait

wait:while(s<=0)do no-op;
s = s – 1;
signal:s = s + 1;

2. Non-Busy waiting Semaphore


其實也是 Counting Semaphore

type Sempahore{
int value;
Q : a FIFO Queue for waiting process
}
Semaphore S;

wait(s): signal(s):
S.value = S.value – 1; S.value = S.value + 1;
if(s.value < 0){ if(s.value <= 0){
add process P to S.Q; romove process P from S.Q;
Block(P);//此為 System call, Wakeup(P);//此為 System call,
//P’s state : running -> Blocked //P’s state : Blocked -> Ready
} }
製作 Semaphore
(一) 想法:如何確保號誌值不會 Race Condition? ( wait / signal 是 atomic
operation )
∴方法
(1)Disable Interrupt
{
(2)C.S Design (SW solution /HW instrutuon support)
(二) 4 種 algo
Semaphore 定
Non-Busy waiting
義 Spinlock Semaphore
Semaphore
製作方法
Disable Interrupt [Algo1] [Algo3]
C.S Design [Algo2] [Algo4]
[Algo1]
Wait(S): Signal(S):
Disable interrupt; Disable interrupt;
S.value = S.value - 1; S.value = S.value + 1;
if(S.value < 0){ if(S.value <= 0){
add process P to S.Q; remove process P from S.Q;
Enable interrupt; Wakeup(P);
Block(P); }
} Enable interrupt;
else
Enable interrupt;

[Algo2]

Disable interrupt 換成 Entry Section


將[Algo1] {
Enable interrupt 換成 Exit Section

而 Entry Section 及 Exit Section 控制碼需另外寫,

SW solution : Bakery' s algo (恐龍已刪)


使用{
HW instruction support : Test-and-Set 或 Swap
[Algo3]
wait(s): signal(s):
Disable interrupt; ○
關 Disable interrupt; ○

while(S <= 0){ S = S – 1;


Enable interrupt; ○
開 Enable interrupt; ○

no-op;
Disable interrupt; ○

}
S = S – 1;
Enable interrupt; ○

[Algo4]:同[Algo2]

Busy-Waiting 是否可以完全避免? (avoid altogether)


No,無法完全避免!
說明:以 Semaphore 為例
定義層次 製作層次
Busy-waiting
Semaphore
Non-Busy 仍用 C.S Design 來作 → Entry Section ← 內有 Busy waiting
waiting
Semaphore
結論:無論使用 SW solution 或 HW instruction support 製作,在 Entry Section 仍有
Busy waiting。
Monitor
(一)定義:Monitor 是用來解決同步的高階資料結構(物件導向)(或高階的 Abstract Data Type)
可讓 Programmer 自己定義所需的 Monitor type 來解決同步 Type。
(Semaphore and monitor have the same power in solving synchronization
problem.)

(1)共享變數宣告區:只有 Monitor 可直接用


• Monitor 定義 3 個組成 {(2)a set of procedure(or function):供外界呼叫
(3)Initialization(初始值設定)區:共享變數設初值

• 其中共享變數區的資料可以被 Monitor 的 procedures (functions)直接存取,外界


不可直接存取,必須透過 Monitor 的 procedure (function)呼叫使用,間接存取。
(二)語法 syntax

type Monitor_monitor-Name{
var : 共享變數宣告;
procedure entry function_1_Name(參數)
begin
body
end
begin
初值設定
end
}

(三)Monitor 本身已經保障是 Mutual exclusion


• 說明:任何時間最多只允許 1 個 process 在 monitor 內活動。
• 流程:若有 1 個 process 已經呼叫 Monitor 的某個 procedure (function)在執行中,那麼
其他 process 就無法呼叫 Monitor 裡的任何 procedure (function)執行,必須等待
到那個 process 完成 procedure (function)的執行或 process 因為某些因素被
Blocked,其他的 process 才可呼叫 Monitor 的 procedure (function)執行。
• 意義:保證共享變數區的資料不會 Race Condition
• 此點比 Semaphore 優秀:Programmer 無須煩惱要寫額外的 code 來防止 Race Condition,
只需宣告在 Monitor 的共享變數區就好,所以 Programmer 就可專
心解決「同步」機制。
(複習 Semaphore:同步條件滿足 + R.C 防止 → Extra code)
Condition 型態的變數 in Monitor
(一)定義:Monitor 會提供 Condition type 的變數給 programmer 使用以解決同步問題。
例:Condition x -> 在 x 上會提供 2 個 operations 供呼叫使用
(1) x.wait -> 像 Blcok()
定義:執行此 operation 的 process 會被 Blocked,且被加入 x 附屬的 waiting Queue
(2) x.signal -> 像 wakeup()
定義:如果有 Process 在 waiting Queue 裡,則此 operation 會從 Queue 移走 1 個
process 並恢復執行,否則此 operation 沒有任何作用(當然多執行也沒差)。
[補充]通常,x 的 waiting Queue 是 FIFO Queue (內定),但也可以是 Priority Queue

使用 Monitor 解決同步問題
例一、The Dinning Philosophers problem
Ⅰ.先定義 Monitor Type

type Monitor Dinning_Philosophers{


var:(1) State[0..4] of (thinking,hungry,eating) //thinking 為初始值
(2) Conditon Self[0..4] //每人有各自的 condition
Procrdure entry pickup(i = 0..4)
begin 哲學家編號
state[i] = hungry;
test(i); //檢查能不能吃飯
if(state[i] != eating)then self[i].wait; //test 失敗,把自己卡住無法吃飯
end
Procedure test(k = 0..4) //test 前不加 entry 表示此 procedure 是 private 的
begin
if(state[(k+1)%5] != eating && state[k] == hungry && state[(k+4)%5] != eating)
{ //左邊沒吃飯 && 自己肚子餓(putdown call test) && 右邊沒吃飯
//同時一定只有一個 Process 在 Monitor 內,左右都不吃則自己一定能吃
state[k] == eating;
self[k].signal; //叫自己起來(有可能被 Blcok 住,而左右的 Process 吃完才作 Test)
}
end
Procedure entry putdown(i=0..4)
begin
state[i] = thinking; //不想吃飯
test((i+1)%5); //給左右哲學家機會,如果左右哲學家的各自左右哲學家 not eating 且
test((i+4)%5); //state = hungry,就可以吃 (救別人)
end
begin
初 for(i = 0 to 4)

區 state[i] = thinking; //設定 thinking 為初始值
end
Ⅱ.使用 Monitor Type
宣告共享變數:

Dinning_Philosophers dp ; / Dinning_Philosophers:Monitor Type,dp:變數名

repeat
hungry now
dp.puckup(i); //成功:進入 C.S(eating now) 失敗:Block 住,等別的 Pj 作 putdown
eating now //當 Pi 進入表示 Pi 不在 Monitor 內:Not Active
dp.putdown(i);
thinking now //Not Active
until false

何謂 Process Not Active in Monitor?



1 founction 完成、離開 Monitor


2 process 卡住 (執行 x.wait)

Condition wait 的 Monitor


(一)定義:通常 condition 變數(e.g. x)的 waiting Queue 是 FIFO Queue,但是有時候需
要 Priority Queue 優先移除最高 priority process。
(二)因此使用 x.wait(c) // c 表 process 的優先權,一併儲存
例二、設計 1 個 Monitor,執行互斥資源的分配且 priority 高者優先分配

與優先權無關:才是設計 Monitor 重點
{與優先權有關:只須告知 Monitor 內的 x 的 waiting Queue 及 entry Queue 是用 priority Queue
即可

Ⅰ.先定義 Monitor Type

type Monitor ResourceAllocator{


true : 已配置
var:(1)bool busy; //代表 Resource 配置與否 {
false : 可用
(2)condition x;
Procedure entry Apply(i:priority 值)
begin
if(busy) x.wait(i); //被卡住了
busy = true; //資源可被用
end
Procedure entry Release()
begin
busy = false;
x.signal(); //救別人
end
begin
busy = false;
end

Ⅱ.使用 Monitor Type Ⅲ.此 Monitor 內 x condition 變數的 waiting


宣告共享變數 Queue 及 Monitor 的 entry Queue 皆採
Resource Allocator RA
priority Queue,priority 高的 process 優
先從 Queue 移除。

Pi 之程式(i 表 process 的優先權){


...

RA.Apply(i);
使用資源
RA.Release(i)
...

}
使用 Monitor 定義 Semaphore (互斥用)

type Monitor Semaphore{ //此為 Counting Semaphore


Var (1)int value; //號誌值
(2)Condition x;
Procedure entry Wait()
begin
value = value – 1;
if(value < 0) //使用 if 而不是 while,因為 1 個出另一個就可進,不必在測 while
x.wait();
end
Procedure entry Signal()
begin
value = value + 1;
x.signal(); //不用加 if(value <= 0),因為有人被 block,siganl 才有用
end
begin
value = 1;
end
Monitor 種類
(一)區分角度(緣由):process B 執行 x.wait 而被卡在 x 的 waiting Queue 中,而目前
process A 在
Monitor 內活動,如果 A 執行 x.signal,則會恢復 B 的執行,此時會變成 A
A 救了 B
和A:救命恩人
B
B:難民
都在 Monitor 內活動,這樣會違反 Monitor 宣稱的互斥性質。
(∴只能讓其中 1 個 process 進行(active))
(二)3 個類型
○1 A wait B until B finish or B is blocked again 難民先

->又稱 Hoare Monitor


○2 B wait A until A finish or A is blocked again 救命恩人先

○3 P exit monitor right now and let B resume execution 救命恩人離開 monitor,

難民恢復執行
->Concurrent C/PASCAL 採用
(三)分析
類型 ○
1 難民先 ○
2 救命恩人先 ○
3 救命恩人離開 monitor,難民恢復執行

優點 (1) 保證難民 保證難民立刻被恢復執行


可立刻被恢
復執行
(2) 比○
3 強大

缺點 不保證難民一定可以 但與○
1 相比,沒那麼強

被恢復執行,因為在 理由:○
3 在救命恩人一進一出 Monitor 其間,

允許救命恩人往下執 頂多救 1 個難民,但○ 1 救命恩人沒有離

行的過程中,可能將 開 Monitor 而是去 Queue 裡等待,所


可以恢復難民執行的 以
條件是改變,使得難 可以救很多難民(需要的話)
民還是卡住
(四)恐龍本分類

(1) 難民先 → Signal-and-wait


{
(2) 救命恩人先 → Signal-and-continue
使用 Semaphore 製作 Monitor
(一)製作 Monitor 必須滿足 3 個需求

(1)保障「互斥」性質
{(2)難民先性質
(3)Condition x 變數的 x.wait 及 x.signal

(二)宣告共享變數

Semaphore mutex = 1 //提供 Monitor 互斥性質之用


Semaphore next = 0 //強迫 A 卡住,if A 執行 x.signal
Semaphore x-sem = 0 //強迫 B 卡住,if B 執行 x,wait
int next-count = 0 //統計 A 個數
int x-count = 0 //統計 B 個數,if x-count = 0 (沒有難民) -> x.signal 無作用

(三)製作 code
(1)確保互斥
方法:在 Monitor 的每個 procedure 開端及尾端加入額外控制碼

wait(mutex)
Body of Procedure
if(next-count > 0) //A 存在
Signal(next); //先救 B
else
Signal(mutex); //放外面的人進來

(2)製作 Condition x 變數

x.wait(){ x.signal(){
x-count++; //B 個數加 1 if(x-count > 0){ //有難民
if(next-count > 0) next-count++; //A 個數加 1
siganl(next); //B 卡住自己之前要先 signal(x-sem); //先救 B
else //解開 mutex wait(next); //A 卡住自己
signal(mutex); //但救命恩人比較重要應先救 next-count--; //if A 被放
wait(x-sem); //B 卡住自己 }
x-count--; //if B 被救 }
}

(四)Monitor 與 Semaphore 解同步問題的能力是相同的 (identical)


原因:雙方可以互相製作(考試時把 code 寫出)
Message Passing 溝通

Symmetric
Direct Communication {
(一)可分為{ Asymmetric
Indirect Communication
(二)Direct Symmetric
定義:○ 收 、○
送 雙方必須指明對方 ID 才可以建立 Communication Link

Send(ID,msg)
指令 {
Receive(ID,msg)
(三) Direct Asymmetric
定義:只有○ 送 需指名 ID,○收 不須指名,所以從任何 process 收到皆可,但收到後要存對方

ID。
(四)Indirect Communication
定義:○ 收 、○送 是透過共享的 Mailbox 才可以建立 Communication Link

Send(Mailbox,msg)
指令 {
Receive(Mailbox,msg)
(五)比較表
Direct(symmetric) Indirect

收 、○
送 雙方必須指明對方 ID 才可以 ○
收 、○
送 是透過共享的 Mailbox 才可

建立 Communication Link 以建立 Communication Link


Communication Link 建立後只專屬 可以多組共享此一 Link
於溝通雙方,不得共享
供通雙方頂多存在 1 條 Link,不可 可以多條 Link 同時存在
多條 Links 同時存在

用 Message Passing 方式解 Producer-Consumer Problem

Producer: Consumer:
repeat repeat
produce an item in nextp Receive(Producer,nextc);
Send(Consumer,nextp); consume the item in nextc
until false until false
在 Message Passing 下,如何呈現同步的感覺?

法一:Link Capacity
用兩種方式呈現 {
法二:Blcoking,Non-Blcoking 的 Send/Receive 指令組合

[法一] Link Capacity


(一)定義:溝通雙方 Communication Link 上會有一附屬的 Message Queue,用來暫存尚未傳遞
的訊息(除了正在傳輸的訊息以外)。
(二)同步呈現方式
Ⅰ.○
收 :必須等到收到○ 送 的訊息後才會往下執行

1. Zero Capacity
Ⅱ.○
送 :Link Capacity { 2. Bounded Capacity
3. Unbounded Capacity
送 送出訊息後,必須等到對方送出訊息,才可往下執行,
1. Zero Capacity:○
此種同步模式也叫 rendezvous (法文約會、偶遇的意思)
A: B:
Send(B,msg) Receive(A,msg)
Receive(B,”Ack”) Send(A,”Ack”)

2. Bounded Capacity:當 Queue 滿了,○ 送 被迫等待

送 無需等待
3. Unbounded Capacity:○
[法二] Blcoking,Non-Blcoking 的 Send/Receive 指令組合

1 Blocking Send:送出訊息後,必須等○ 收 收到,才往下執行


2 Non-Blocking Send:無須等待

3 Blocking Receive:收到訊息後才可往下執行

4 Non-Blcoking Receive:不管收到的訊息有沒有效,仍可往下執行

例外處理 Exception Handling


[1]在 Rendezvous 模式下,A 死亡而 B 卻不知道,會造成 B waiting forever。
O.S 解法:(1)把 B 也終止
(2)通知 B 取消動作
[2]在 Direct Symmetric 模式,有 New process 加入或 resume,則必須讓全部 processes 知道
此 process ID 且他也必須知道其他人的 ID,這樣才能溝通。
[3]Message lost 處理:通常是 OS 負責偵測(Time out)此事,若 Message lost,則 OS 會通知
Sender 重送。

You might also like