1. 程式人生 > 實用技巧 >c++讀寫鎖--讀者寫者問題

c++讀寫鎖--讀者寫者問題

又名:共享-互斥鎖,多讀者-單寫者鎖。

允許多個讀者進入臨界區,因為只讀資料是安全的;

只允許單寫者進入臨界區。

所以,讀者進入臨界區時,第一個讀者對臨界區資源加一次鎖,最後一個讀者解鎖(所以又名:共享鎖,讀鎖);寫者進入臨界區時,每次都需要對臨界區加鎖解鎖(又名:排他鎖,寫鎖)。

注:semaphore訊號量的值為1,等同於互斥量使用。

第一種實現,讀優先

 1 semaphore resource=1;
 2 semaphore rmutex=1;
 3 readcount=0;
 4 
 5 /*
 6    resource.P() is equivalent to wait(resource)
7 resource.V() is equivalent to signal(resource) 8 rmutex.P() is equivalent to wait(rmutex) 9 rmutex.V() is equivalent to signal(rmutex) 10 */ 11 12 writer() { 13 resource.P(); //Lock the shared file for a writer 14 15 <CRITICAL Section> 16 // Writing is done 17 18
<EXIT Section> 19 resource.V(); //Release the shared file for use by other readers. Writers are allowed if there are no readers requesting it. 20 } 21 22 reader() { 23 rmutex.P(); //Ensure that no other reader can execute the <Entry> section while you are in it
24 <CRITICAL Section> 25 readcount++; //Indicate that you are a reader trying to enter the Critical Section 26 if (readcount == 1) //Checks if you are the first reader trying to enter CS 27 resource.P(); //If you are the first reader, lock the resource from writers. Resource stays reserved for subsequent readers 28 <EXIT CRITICAL Section> 29 rmutex.V(); //Release 30 31 // Do the Reading 32 33 rmutex.P(); //Ensure that no other reader can execute the <Exit> section while you are in it 34 <CRITICAL Section> 35 readcount--; //Indicate that you are no longer needing the shared resource. One fewer reader 36 if (readcount == 0) //Checks if you are the last (only) reader who is reading the shared file 37 resource.V(); //If you are last reader, then you can unlock the resource. This makes it available to writers. 38 <EXIT CRITICAL Section> 39 rmutex.V(); //Release 40 }

第一個讀者進入時,將資源加鎖,從而安全訪問臨界區,不會被寫者修改;由於需要對讀者計數,所以需要一個rmutex互斥量來保護readcount修改的安全。讀者數為0時,釋放資源鎖。

第二種實現,寫優先

 1 int readcount, writecount;                   //(initial value = 0)
 2 semaphore rmutex, wmutex, readTry, resource; //(initial value = 1)
 3 
 4 //READER
 5 reader() {
 6 <ENTRY Section>
 7   readTry.P();                 //Indicate a reader is trying to enter
 8   rmutex.P();                  //lock entry section to avoid race condition with other readers
 9   readcount++;                 //report yourself as a reader
10   if (readcount == 1)          //checks if you are first reader
11     resource.P();              //if you are first reader, lock  the resource
12   rmutex.V();                  //release entry section for other readers
13   readTry.V();                 //indicate you are done trying to access the resource
14 
15 <CRITICAL Section>
16 //reading is performed
17 
18 <EXIT Section>
19   rmutex.P();                  //reserve exit section - avoids race condition with readers
20   readcount--;                 //indicate you're leaving
21   if (readcount == 0)          //checks if you are last reader leaving
22     resource.V();              //if last, you must release the locked resource
23   rmutex.V();                  //release exit section for other readers
24 }
25 
26 //WRITER
27 writer() {
28 <ENTRY Section>
29   wmutex.P();                  //reserve entry section for writers - avoids race conditions
30   writecount++;                //report yourself as a writer entering
31   if (writecount == 1)         //checks if you're first writer
32     readTry.P();               //if you're first, then you must lock the readers out. Prevent them from trying to enter CS
33   wmutex.V();                  //release entry section
34   resource.P();                //reserve the resource for yourself - prevents other writers from simultaneously editing the shared resource
35 <CRITICAL Section>
36   //writing is performed
37   resource.V();                //release file
38 
39 <EXIT Section>
40   wmutex.P();                  //reserve exit section
41   writecount--;                //indicate you're leaving
42   if (writecount == 0)         //checks if you're the last writer
43     readTry.V();               //if you're last writer, you must unlock the readers. Allows them to try enter CS for reading
44   wmutex.V();                  //release exit section
45 }

寫者優先,所以當第一個寫者進入時,嘗試對讀者加鎖,讓後面的讀者阻塞,即readTry.P();增加了writecount寫者計數,不為0時,不會讓讀者進入,即readTry.V();寫者對臨界區的訪問仍然需要互斥進行,即resource.P(),resource.V();wmutex是為了保護計數的。

第三種實現,讀者寫者都公平

 1 int readcount;                // init to 0; number of readers currently accessing resource
 2 
 3 // all semaphores initialised to 1
 4 semaphore resource;           // controls access (read/write) to the resource
 5 semaphore rmutex;             // for syncing changes to shared variable readcount
 6 semaphore serviceQueue;       // FAIRNESS: preserves ordering of requests (signaling must be FIFO)
 7 
 8 //READER
 9 reader() {
10 <ENTRY Section>
11   serviceQueue.P();           // wait in line to be serviced
12   rmutex.P();                 // request exclusive access to readcount
13   readcount++;                // update count of active readers
14   if (readcount == 1)         // if I am the first reader
15     resource.P();             // request resource access for readers (writers blocked)
16   serviceQueue.V();           // let next in line be serviced
17   rmutex.V();                 // release access to readcount
18     
19 <CRITICAL Section>
20 //reading is performed
21     
22 <EXIT Section>
23   rmutex.P();                 // request exclusive access to readcount
24   readcount--;                // update count of active readers
25   if (readcount == 0)         // if there are no readers left
26     resource.V();             // release resource access for all
27   rmutex.V();                 // release access to readcount
28 }
29 
30 //WRITER
31 writer() {
32 <ENTRY Section>
33   serviceQueue.P();           // wait in line to be serviced
34   resource.P();               // request exclusive access to resource
35   serviceQueue.V();           // let next in line be serviced
36     
37 <CRITICAL Section>
38 // writing is performed
39     
40 <EXIT Section>
41   resource.V();               // release resource access for next reader/writer
42 }

與第一種讀優先比較,多了一個serviceQueue互斥鎖,讀者寫者同時請求這個互斥鎖,以此達到公平競爭的目的。

Reference:

https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem