讀者寫者問題——讀者優先,寫者優先,公平競爭 解決方法
本篇主要是從讀者寫者問題中的讀者優先、寫者優先、以及兩者公平競爭三個方面解析。
至於誰優先的問題,主要從以下兩個方面來判斷:
1、當優先順序低的程序獲得臨界區時,高優先順序程序能從低優先順序程序中搶得臨界區的訪問權
2、當優先順序高的程序在訪問臨界區時,低優先順序程序必須等待,直到高優先順序全部訪問完才有機會訪問臨界區
可以將所有讀者和所有寫者分別存於一個讀者等待佇列和一個寫者等待佇列中,每當讀允許時,就從讀者佇列中釋放一個或多個讀者執行緒進行讀操作;
當寫允許時,就從寫者佇列中釋放一個寫者執行緒進行寫操作。
讀者優先。讀者優先指的是除非有寫者在寫檔案,否則讀者不需要等待。所以可以用一個整數變數Read_count記錄當前的讀者數目,用於確定是否需要釋放正在等待的寫者程序(當Read_count=0時,表明所有的讀者讀完,需要釋放寫者等待佇列中的一個寫者)。每當一個讀者開始讀檔案時,必須修改Read_count變數。因此需要一個互斥物件mutex來實現對全域性變數Read_count修改時的互斥。
另外,為了實現讀-寫互斥,需要增加一個臨界區物件Write。當寫者發出寫請求時,必須申請臨界區物件的所有權。通過這種方法,可以實現讀-寫互斥,當Read_count=1時(即第一個讀者到來時),讀者執行緒也必須申請臨界區物件的所有權。
當讀者擁有臨界區的所有權時,寫者阻塞在臨界區物件Write上。當寫者擁有臨界區的所有權時,第一個讀者判斷完”Read_count==1”後阻塞在Write上,其餘的讀者由於等待對Read_count的判斷,阻塞在mutex上。
寫者優先。寫者優先與讀者優先相類似。不同之處在於一旦一個寫者到來,它應該儘快對檔案進行寫操作,如果有一個寫者在等待,則新到來的讀者不允許進行讀操作。為此應當填加一個整形變數Write_count,用於記錄正在等待的寫者的數目,當Write_count=0時,才可以釋放等待的讀者執行緒佇列。
為了對全域性變數Write_count實現互斥,必須增加一個互斥物件mutex3。
為了實現寫者優先,應當填加一個臨界區物件read,當有寫者在寫檔案或等待時,讀者必須阻塞在read上。
讀者執行緒除了要對全域性變數Read_count實現操作上的互斥外,還必須有一個互斥物件對阻塞read這一過程實現互斥。這兩個互斥物件分別命名為mutex1,mutex2。
總結:以上內容很清楚的講述了程序間通訊之經典問題—"讀者—寫著"問題的本質,並且提出了實現的方法,可以幫助讀者學好作業系統這門核心的計算機專業課程。
讀者優先演算法:
分析:讀者優先是指:除非有寫者正在寫檔案,否則讀者不需要等待,可以定義一個readcount變數用來統計有多少個讀者正在讀檔案,用於確定是否需要釋放正在等待 的 程序(readcount == 0 ,則表明讀者已經訪問完畢,需要釋放等待佇列中的一個寫者程序),由於readcount是臨界資源,需要定義一個訊號量Rmutex來互斥的對 其 進行訪問。另外為了實現讀者與寫者、寫者與寫者之間互斥的對檔案的訪問,定義一個訊號量fmutex來實現
-
fmutex = 1//讀者、寫者程序訪問檔案訊號量變數,保證了讀者與寫者、寫者與寫者之間的互斥訪問
- Rmutex = 1//實現對readcount的互斥訪問
- Read()
- {
- while(1)
- {
- wait(Rcount) ;
- if(0 == readcount)
- wait(fmutex) ;
- readcount ++ ;
- signal(Rcount) ;
- ......
- perform reading operation
- ......
- wait(Rcount);
-
readcount --;
- if(0 == readcount)
- signal(fmutex)
- signal(Rcount) ;
- }
- }
- Writer()
- {
- while(1)
- {
- wait(Entmutex)//保證每次阻塞在fmutex中的寫者程序只有一個
- wait(fmutex)
- ......
- perform writing operation
- ......
- signal(fmutex)
- signal(Entmutex)
- }
- }
分析一下問什麼是讀者優先:
1、首先當讀者獲得臨界區的訪問權,則此時的readcount > 0 則讀者尚未釋放fmutex則寫者就不能獲得臨界區的訪問權,有一個被阻塞在fumtex訊號中,其餘的被塞 在Entmutex訊號中,則只有當讀者訪問完畢,寫者才有機會獲得臨界區的訪問權
2、若寫者獲得臨界區的訪問權,而且有源源不斷的寫著程序過來,那麼讀者能不能搶得臨界區的訪問權呢?答案是肯定的,因為考慮此時的讀者程序阻塞情況,有一個讀者程序阻塞在fmutex中,其餘的讀者均阻塞在Rmutex,而寫者程序呢,由於Entemutex的存在每個時刻只有一個一個寫者程序阻塞在fmutex中,其餘的全被阻塞在Entmutex中,則當寫者程序訪問完畢後,此時阻塞在fmutex中的程序只有讀者程序,則也就只有讀者程序先被啟用訪問
寫者優先:
分析:寫者優先與讀者優先相類似。不同之處在於一旦一個寫者到來,它應該儘快對檔案進行寫操作,如果有一個寫者在等待,則新到來的讀者不允許進行讀操作。為此應當填加一個整形變數Write_count,用於記錄正在等待的寫者的數目,當Writecount=0時,才可以釋放等待的讀者執行緒佇列。為了對writecount實現互斥,則定義一個互斥訊號量Wcmutex=1.
為了實現寫者優先,應當填加一個臨界區物件read,當有寫者在寫檔案或等待時,讀者必須阻塞在read上。
讀者執行緒除了要對全域性變數Read_count實現操作上的互斥外,還必須有一個互斥物件對阻塞read這一過程實現互斥。這兩個互斥物件分別命名為Entemutex,Quemutex。
訊號量queMutex標示一個隊訊號量,來的程序都現在這裡面排隊,Entermutex的存在則是保證阻塞 在Quemutex中的讀者程序最多隻有一個
- Reader()
- {
- while(1)
- {
- wait(Entemutex)
- wait(Quemutex)
- wait(Rcount)
- if(0 == readcount)
- wait(fmutex)
- readcount ++
- wait(Rcount)
- wait(Quemutex)
- wait(Entemutex)
- ........
- perform reading opreation
- ........
- wait(Rcount)
- if(readcount == 0)
- signal(fmutex)
- signal(Rcount)
- }
- }
- writer()
- {
- while(1)
- {
- wait(Wcount)
- if(writecount == 0)
- wait(Quemutex)
- writecount ++
- signal(Wcount)
- wait(fmutex)
- ........
- perform writing operation
- ........
- signal(fmtex)
- wait(Wcount)
- readcount--
- if(readcount == 0)
- signal(Quemutex)
- signal(Wcount)
- }
- }
分析:這個為什麼是寫者優先?
1.當讀者獲得了訪問臨界區的權利時,且讀者程序訪問的很密集時(即很多讀者都需要訪問),寫者如何搶得訪問權。
由於Entmutex的存在每次阻塞在Quemutex中的讀者程序最多隻有一個,而當讀者程序訪問時,寫著程序一個被阻塞在Quemutex中,其餘的全部阻塞在Wcount中,當讀者訪問完畢,釋放Quemutex,此時,阻塞在其中的程序只有寫者程序,則寫著程序得到啟用
2.當寫者獲得臨界區的訪問權時,讀者只能等到臨界區空閒時才能得到臨界區訪問權。
因為當寫者獲得臨界區時,所有的讀者都會阻塞在Entmutex訊號和QUemutex訊號中。 而只有最後一個寫者訪問完臨界區時,才會Signal(Qmutex), 使得阻塞在fmutex中唯一的讀者獲得臨界區訪問權。
公平競爭:
- Reader()
- {
- while(1)
- {
- wait(Quemutex)
- wait(Rcount)
- if(0 == readcount)
- wait(fmutex)
- readcount ++
- wait(Rcount)
- wait(Quemutex)
- ........
- perform reading opreation
- ........
- wait(Rcount)
- if(readcount == 0)
- signal(fmutex)
- signal(Rcount)
- }
- }
- writer()
- {
- while(1)
- {
- wait(Quemutex)
- wait(fmutex)
- ........
- perform writing operation
- ........
- signal(fmtex)
- signal(Qmutex)
- }
- }