c++讀寫鎖--讀者寫者問題
阿新 • • 發佈:2020-12-07
又名:共享-互斥鎖,多讀者-單寫者鎖。
允許多個讀者進入臨界區,因為只讀資料是安全的;
只允許單寫者進入臨界區。
所以,讀者進入臨界區時,第一個讀者對臨界區資源加一次鎖,最後一個讀者解鎖(所以又名:共享鎖,讀鎖);寫者進入臨界區時,每次都需要對臨界區加鎖解鎖(又名:排他鎖,寫鎖)。
注: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 it24 <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