作業系統概念(高等教育出版社,第七版)複習——第六章:程序同步
第六章 程序同步
基礎知識
競爭條件
多個程序併發訪問和操作同一資料且執行結果與訪問發生的特定順序有關,稱為競爭條件。
原子操作(Atomic Operation):
指一個操作中的所有動作要麼全做,要麼全不做;
該操作是一個不可分割的單位;
在執行過程中不允許被中斷;
這些原子操作在管態(核心態)下執行;
常駐記憶體;
原語(Primitive):
是完成一定功能的一個過程
與一般程式段的不同是,它是原子操作。
原語是一段程式,與一般程式的不同點是,這段程式在執行期間不允許被中斷;
這段程式要麼全執行,要麼全不執行
臨界區問題
在程式中訪問臨界資源的那段程式碼稱為臨界區;
將對臨界資源的互斥訪問轉化為對臨界區的互斥訪問。
臨界區問題的解答必須滿足如下三項要求:
互斥、前進、有限等待。
do {
進入區entry section
臨界區critical section
退出區exit section
剩餘區reminder section
} while(true)
臨界資源
把在一段時間內只允許一個程序訪問的資源稱為臨界資源。
臨界資源要求互斥地共享,或互斥地訪問。
硬體同步
do {
請求鎖
臨界區critical section
釋放鎖
剩餘區reminder section
} while(true)
訊號量
是一個受保護的量,對其只能進行初始化(即賦初值)以及wait及signal操作
<注>:
wait (S) { //申請一個資源
while S <= 0; // no-op
S--;
}
signal (S) { //釋放一個資源
S++;
}
當訊號量S.value大於0的時候,代表可用資源數目,小於零的時候代表等待佇列長度。
經典同步問題(超級重要)
生產者消費者問題
有界緩衝問題
讀者寫者問題
哲學家吃飯問題
理髮師/看病問題
吸菸者問題
管程
課後作業
6.3
當一個程序位於其臨界區內,任何試圖進入其臨界區的程序都必須在進入程式碼連續迴圈。忙等待可以被避免,但是承擔這種開銷與讓一個程序處於沉睡狀態,當相應程式的狀態達到的時候程序又被喚醒有關。
6.4
不適合單處理器原因:自旋鎖不適合在單處理器系統是因為從自旋鎖中打破一個程序的條件只有在執行一個不同的程序時才能獲得。
適合多處理器原因:一個執行緒在一個處理器上等待,而另一個執行緒可以在另一個處理器上訪問臨界區;當一個程序等待另一個程序產生的事件,另一個程序可以在其它處理機上執行從而產生該事件。
6.5
如果一個使用者級程式具有停止中斷的能力,那麼它能夠停止計時器中斷,防止上下文切換的發生,從而允許它使用處理器而不讓其他程序執行。
6.6
在多處理器系統中,程序在某一個處理器停止中斷不能保證互斥進入程式狀態。
6.8
int empty = N;
int full = 0;
int mutex = 1;
連線:
while(1) {
wait(empty);
wait(mutex);
connect();
signal(mutex);
signal(full);
}
釋放:
While(1) {
wait(full);
wait(mutex);
release();
signal(mutex);
signal(empty);
}
6.9
當執行wait時,執行到s--的時候,發生中斷,然後執行signal的s++,發生中斷,接著執行wait,此時s不小於0,不能執行if語句,這樣會發生混亂。反之亦然。所以wait和signal為原子操作,都不能被打斷。
6.11
訊號量:
int mutex=1;
int customer=0;
int barberReady=0;
int waiting=0
CHAIR = N;
理髮師:
while(1) {
waiting(customer);
waiting(mutex);
waiting= waiting--;
signal(mutex);
signal(barberReady);
cuthair();
}
顧客:
while(1) {
wait(mutex);
if(waiting<CHAIR){
waiting++;
signal(mutex);
singal(customers);
wait(barberReady);
}else{
signal(mutex);
leaving();
}
6.13
Monitor bounded_buffer {
intitems[MAX_ITEMS];
intnumItems = 0;
conditionfull, empty;
voidproduce(int v) {
while(numItems==MAX_ITEMS)
full.wait();
iems[numItems++]=v;
empty.signal();
}
intconsume() {
intretVal;
while(numItems==0)
empty.wait();
retVal=items[--numItems];
full.signal();
returnretVal;
}
}
6.22
Monitor alarm {
conditionc;
voiddelay(int ticks) {
intbegin_time = read_clock();
while(read_clock()<begin_time+ ticks)
c.wait();
}
void tick() {
c.broadcast();
}
}
思考題:
Concepts:
race condition:多個程序併發訪問和操作同一資料,且執行結果與訪問發生的特定順序有個條件關,稱為競爭條件。
critical reource:把在一段時間內只允許一個程序訪問的資源稱為臨界資源。
critical section:在程式中訪問臨界資源的那段程式碼稱為臨界區。
atomic operation:原子操作是指不能被中斷的操作。
Semaphoer:訊號量是一個受保護的量,對其只能進行初始化(即賦初值)和wait及signal操作。
wait() and signal() operation:測試,增加。
Monitor:管程是一種程式結構,結構內的多個子程式(物件或模組)形成的多個工作執行緒互斥訪問共享資源。這些共享資源一般是硬體裝置或一群變數。
如何利用硬體TestAndSet Instruction以及swap Instruction實現臨界區的互斥?
booleanTestAndSet(boolean *target) {
boolean rv =*target;
*target =TRUE;
return rv;
}
void Swap(boolean*a, boolean *b) {
boolean temp =*a;
*a = *b;
*b = temp;
}
給出教材中討論的三個經典問題、以及The Sleeping-Barber Problem及Cigarette Smoker’sProblem的問題描述,說明程序之間的制約關係,利用訊號量及wait、signal操作給出能正確執行的程式
a) 生產者-消費者問題
semaphoremutex = 1, empty = n, full = 0;
i. 生產者
do {
wait(empty);
wait(mutex);
//放數
signal(mutex);
signal(full);
}while(TRUE);
ii. 消費者
do {
wait(full);
wait(mutex);
//取數
signal(mutex);
signal(empty);
}while(TRUE);
b) 讀者-寫者問題
i. 寫者
semaphore mutex =1, wrt = 1;
int readcount =0;
do {
wait(wrt);
//寫
signal(wrt);
}while(TRUE);
ii. 讀者
do {
wait(mutex);
readcount++;
if(readcount== 1)
wait(wrt);
signal(mutex);
//讀
wait(mutex);
readcount--;
if(readcount== 0)
signal(wrt);
signal(mutex);
}while(TRUE);
c) 哲學家進餐問題
i. 哲學家i
do {
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
//eat
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
//think
}while(TRUE);
d) 睡眠理髮師問題
int chairs =n, waiting = 0;
semaphorecustomer = 0, barber = 0, mutex = 1;
i. 理髮師
while(1) {
wait(customer);
signal(barber);
wait(mutex);
waiting--;
signal(mutex);
//理髮
}
ii. 顧客
while(1) {
wait(mutex);
waiting++;
if(waiting<n)
signal(mutex);
signal(customer);
wait(barber);
//理髮
}
e) 吸菸者問題
i. 供應者
int which =1+rand()%3;
wait(done_smoking);
//生產材料
switch(which){
case 1:
signal(paper_glue);
break;
case 2:
signal(tobacco_glue);
break;
case 3:
signal(tobacco_paper);
break;
}
ii. 吸菸者
switch(number){
case 1:
wait(paper_glue);
//吸菸
break;
case 1:
wait(tobacco_glue);
//吸菸
break;
case 1:
wait(tobacco_paper);
//吸菸
break;
}
signal(done_smoking);