1. 程式人生 > >讀寫者問題

讀寫者問題

一、PV操作

1、訊號量
PV操作與訊號量的處理有關,訊號量是表示資源的實體,是一個與佇列有關的整型變數,其值只能由P、V操作來改變。作業系統利用訊號量對程序和資源進行控制和管理。

2、PV操作實現
訊號量(Saphore)由一個值和一個指標組成,指標指向等待該訊號量的程序。訊號量的值表示相應資源的使用情況。訊號量S>=0時,S表示可用資源的數量。執行一次P操作意味著請求分配一個資源,因此S的值減1;當S<0時,表示已經沒有可用資源,S的絕對值表示當前等待該資源的程序數。請求者必須等待其他程序釋放該類資源,才能繼續執行。而執行一個V操作意味著釋放一個資源,因此S的值加1;若S<0,表示有某些程序正在等待該資源,因此要喚醒一個等待狀態的程序,使之執行下去。

procedure P(var s:samephore);
{
    s.value=s.value-1;
    if (s.value<0) 
    asleep(s.queue);
}
procedure V(var s:samephore);
{
    s.value=s.value+1;
    if (s.value<=0) 
    wakeup(s.queue);
}

其中用到兩個標準過程:

asleep(s.queue):執行此操作的程序的PCB進入s.queue尾部,程序變成等待狀態

wakeup(s.queue):將s.queue頭程序喚醒插入就緒佇列

s的初值為1時,可以用來實現程序的互斥,執行流程必須是P操作,V操作,P操作,V操作…

二、讀寫者問題
問題描述:
有讀者和寫者兩組併發程序,共享一個檔案,當兩個或以上的讀程序同時訪問共享資料時不會產生副作用,但若某個寫程序和其他程序(讀程序或寫程序)同時訪問共享資料時則可能導致資料不一致的錯誤。因此要求:①允許多個讀者可以同時對檔案執行讀操作;②只允許一個寫者往檔案中寫資訊;③任一寫者在完成寫操作之前不允許其他讀者或寫者工作;④寫者執行寫操作前,應讓已有的讀者和寫者全部退出。
1、讀者優先

  1. 關係分析。由題目分析讀者和寫者是互斥的,寫者和寫者也是互斥的,而讀者和讀者不存在互斥問題。

  2. 整理思路。兩個程序,即讀者和寫者。寫者是比較簡單的,它和任何程序互斥,用互斥訊號量的P操作、V操作即可解決。讀者的問題比較複雜,它必須實現與寫者互斥的同時還要實現與其他讀者的同步,因此,僅僅簡單的一對P操作、V操作是無法解決的。那麼,在這裡用到了一個計數器,用它來判斷當前是否有讀者讀檔案。當有讀者的時候寫者是無法寫檔案的,此時讀者會一直佔用檔案,當沒有讀者的時候寫者才可以寫檔案。同時這裡不同讀者對計數器的訪問也應該是互斥的。

  3. 訊號量設定。首先設定訊號量count為計數器,用來記錄當前讀者數量,初值為0; 設定mutex為互斥訊號量,用於保護更新count變數時的互斥;設定互斥訊號量rw用於保證讀者和寫者的互斥訪問。

int count=0;  //用於記錄當前的讀者數量
semaphore mutex=1;  //用於保護更新count變數時的互斥
semaphore rw=1;  //用於保證讀者和寫者互斥地訪問檔案
writer () {  //寫者程序
    while (1){
        P(rw); // 互斥訪問共享檔案
        Writing;  //寫入
        V(rw) ;  //釋放共享檔案
    }
}
 
reader () {  // 讀者程序
    while(1){
        P (mutex) ;  //互斥訪問count變數
        if (count==0)  //當第一個讀程序讀共享檔案時
            P(rw);  //阻止寫程序寫
        count++;  //讀者計數器加1
        V (mutex) ;  //釋放互斥變數count
        reading;  //讀取
        P (mutex) ;  //互斥訪問count變數
        count--; //讀者計數器減1
        if (count==0)  //當最後一個讀程序讀完共享檔案
            V(rw) ;  //允許寫程序寫
        V (mutex) ;  //釋放互斥變數 count
    }
}

2、寫者優先
在上面的演算法中,讀程序是優先的,也就是說,當存在讀程序時,寫操作將被延遲,並且只要有一個讀程序活躍,隨後而來的讀程序都將被允許訪問檔案。這樣的方式下,會導致寫程序可能長時間等待,且存在寫程序“餓死”的情況。

如果希望寫程序優先,即當有讀程序正在讀共享檔案時,有寫程序請求訪問,這時應禁止後續讀程序的請求,等待到已在共享檔案的讀程序執行完畢則立即讓寫程序執行,只有在無寫程序執行的情況下才允許讀程序再次執行。為此,增加一個訊號量並且在上面的程式中 writer()和reader()函式中各增加一對PV操作,就可以得到寫程序優先的解決程式。

int count = 0;  //用於記錄當前的讀者數量
semaphore mutex = 1;  //用於保護更新count變數時的互斥
semaphore rw=1;  //用於保證讀者和寫者互斥地訪問檔案
semaphore w=1;  //用於實現“寫優先”
 
writer(){
    while(1){
        P(w);  //在無寫程序請求時進入
        P(rw);  //互斥訪問共享檔案
        writing;  //寫入
        V(rw);  // 釋放共享檔案
        V(w) ;  //恢復對共享支件的訪問
    }
}
 
reader () {  //讀者程序
    while (1){
        P (w) ;  // 在無寫程序請求時進入
        P (mutex);  // 互斥訪問count變數
 
        if (count==0)  //當第一個讀程序讀共享檔案時
            P(rw);  //阻止寫程序寫
 
        count++;  //讀者計數器加1
        V (mutex) ;  //釋放互斥變數count
        V(w);  //恢復對共享檔案的訪問
        reading;  //讀取
        P (mutex) ; //互斥訪問count變數
        count--;  //讀者計數器減1
 
        if (count==0)  //當最後一個讀程序讀完共享檔案
            V(rw);  //允許寫程序寫
 
        V (mutex);  //釋放互斥變數count
    }
}

3、公平競爭