1. 程式人生 > >作業系統5————程序同步的經典問題:司機售票員&問題生產者消費者問題&哲學家進餐問題&讀者寫者問題

作業系統5————程序同步的經典問題:司機售票員&問題生產者消費者問題&哲學家進餐問題&讀者寫者問題

作業系統5————程序同步的經典問題:司機售票員&問題生產者消費者問題&哲學家進餐問題&讀者寫者問題

一. 目錄

二. 訊號量的簡單應用

1. 使用訊號量實現互斥

思路:設mutex為互斥訊號量,其初值為1,取值範圍為(-1,0,1)。當mutex=1時,表示兩個程序皆未進入需要互斥的臨界區,當mutex=0時,表示有一個程序進入臨界區。另一個必須等待,掛入阻塞佇列。當muntex=-1時,表示有一個程序因等待而阻塞在訊號量佇列,需要被當前已在臨界區執行的程序推出是喚醒

程式碼描述

semaphore mutex = 1;

pA(){
    while(1){
        wait(mutex);
        臨界區
        signal(mutex);
        剩餘區
    }
}


PB(){
    while(1){
        wait(mutext);
        臨界區;
        signal(mutex);
        剩餘區
    }
}

2. 使用訊號量實現前驅關係

問題: 現在有程序P1和P2,P1有語句S1,P2有語句S2,我們希望執行完S1後在執行S2。 思路: 我們只需要在程序P1和P2之間共享一個公用訊號量S,並且賦其初值為0,將signal(S)操作放在語句S1後,而把S2語句前面插入Wait(S)操作。 虛擬碼

在程序P1中: S1; signal(S);
在程序P2中:wait(S);s2;

三. 司機售票員問題

1. 問題描述

公共汽車上。司機和售票員的活動分別如下: 司機的活動:啟動車輛,正常行車,到站停車. 售票員的活動: 關車門,售票,開車門。

2. 思路

分析可知。售票員和司機的4個活動存在前後關係。即關車門–>啟動汽車。到站停車–>開車門。所以用兩個訊號量s1,s2分別來控制兩組前後關係.

3. 使用記錄型訊號量解決問題

虛擬碼

semaphore s1 = 1,s2 = 1;
//司機
void driver(){
	signal(s1)
	啟動車輛
	正常行駛
	到站停車
	wait(s2)
}

void conductor(){
	關車門
	wait(s1)
	售票
	signal(s2)
	開門
}

四. 生產者消費者(快取繫結問題)問題

1. 問題描述

有兩個程序:一組生產者程序和一組消費者程序共享一個初始為空、固定大小為n的快取(緩衝區)。生產者的工作是製造一段資料,只有緩衝區沒滿時,生產者才能把訊息放入到緩衝區,否則必須等待,如此反覆; 同時,只有緩衝區不空時,消費者才能從中取出訊息,一次消費一段資料(即將其從快取中移出),否則必須等待。由於緩衝區是臨界資源,它只允許一個生產者放入訊息,或者一個消費者從中取出訊息。

2. 思路

問題的核心是:

  1. 要保證不讓生產者在快取還是滿的時候仍然要向內寫資料;
  2. 不讓消費者試圖從空的快取中取出資料。

生產者和消費者對緩衝區互斥訪問是互斥關係,同時生產者和消費者又是一個相互協作的關係,只有生產者生產之後,消費者才能消費,他們也是同步關係。

3. 使用訊號量解決問題

說明:

假定在生產者和消費者之間的公用快取池具有n個緩衝區,這時候可利用互斥訊號量mutex來實現諸程序對快取池的互斥利用;利用訊號量的empty和full分別表示快取池中空快取區和滿快取區的數量。

虛擬碼描述:

int in=0,out=0;
item buffer[n];
semaphore mutex =1,empty = n,full = 0;

//生產者
void producer(){
    do{
        producer an item nextp;
        ···
        wait(empty);  //詢問是否有空快取區
        wait(mutex); //互斥訪問
        buffer[in] = nextp;
        in = (in+1)%n;
        signal(mutex);//解除互斥訪問
        signal(full); //釋放一個滿快取區,滿快取+1
    }while(TRUE)
}

//消費者
void consumer(){
    do{
        wait(full);
        wait(mutex);
        nextc = buffer[out];
        out = (out+1) %n;
        signal(mutex);
        signal(empty);
    }while(TRUE)
}

當然也可以使用AND訊號量解決問題:即用Swait(empty,mutex)來代替wait(empty);wait(mutex); 用Ssignal(mutex,full)來代替signal(mutex)和signal(full);

五. 哲學家進餐問題

1. 問題描述

有五個哲學家公用一張圓桌,分別坐在周圍的五個椅子上,在圓桌上有五個碗和五隻筷子,他們的生活方式就是交替的進行思考和進餐。平時,一個哲學家進行思考,飢餓是便試圖取其左右最靠近他的筷子,只有在他同時拿到兩隻筷子時才能進餐。進餐畢,放下筷子繼續思考

2. 思路

分析可知,筷子是臨界資源,在一段時間內只允許一位哲學家使用,為了實現對筷子的互斥使用,為了實現對筷子的互斥使用,可以用一個訊號量表示一隻筷子,由這五個訊號量構成訊號量陣列。

3. 使用記錄型訊號量解決問題

虛擬碼

semaphore chopstick[5] = {1,1,1,1,1};

//第i位哲學家的活動可描述為:
do{
    wait(chopstick[i]);
    wait(chopstick[(i+1)%5]);
    ···
    //eat
    ···
    signal(chopstick[i]);
    signal(chopstick[(i+1)%5];
    ···
    //think
    ···
}while(TRUE)

4.分析

上面的解法雖然保證了相鄰的哲學家不會同時進餐,但可能會導致死鎖問題,比如說,當5個哲學家同時飢餓而去拿左邊的筷子是,就會發生死鎖。

避免死鎖的方法:

  1. 至多隻允許有4位哲學家同時去拿左邊的筷子,最終能保證至少有一位哲學家能夠進餐。
  2. 僅當哲學家左右兩隻筷子同時可用時,才允許他拿起筷子進餐。、
  3. 規定奇數號哲學家先拿他左邊的筷子,然後再去拿他右邊的筷子,而偶數號哲學家則相反

六. 讀者寫者問題

1. 問題描述

一個數據檔案可以被多個檔案共享,我們把只要求讀檔案的程序稱為 “Reader程序”,其他程序則稱為“Writer程序”。允許多個程序讀一個檔案,但不允許一個Writer程序和其他Reader程序或者Writer程序同時訪問共享。

2. 思路

由題意可知,讀者之間不互斥,寫者之間互斥,寫者和讀者之間互斥。所以為寫者之間,寫者和讀者之間設定互斥訊號量wmutex。在設定一個整形變數readcount表示讀程序的程序數目。當readcount=0時,才允許寫者執行·。對於讀者而言readcount是一個可被多個讀者訪問的臨界資源。因此,也應該為它設定一個互斥訊號量rmutex。

3. 使用記錄型訊號量解決問題

虛擬碼

semaphore rmutex = 1,wmutex = 1;
int readcount = 0;
void reader(){
	do{
		wait(rmutex);
		if(readcount==0) wait(wmutex);
		readcount++;
		signal(rmutex);
		···
		perform read operation;
		···
		wait(rmutex);
		if(readcount==0) signal(wmutex);
		readcount--;
		signal(rmutex);
	}while(TRUE);
}

void writer(){
	do{
		wait(wmutex);
		perfrom write operation;
		signal(wmutex); 
	}while(TRUE);
}

七.參考資料