操作系统原理:读写者经典同步问题
讀者-寫者問題的讀寫操作限制:
- 寫-寫互斥,即不能有兩個寫者同時進行寫操作。
- 讀-寫互斥,即不能同時有一個線程在讀,而另一個線程在寫。
- 讀-讀允許,即可以有一個或多個讀者在讀。
一、讀者優先
當讀者優先時,寫文件的線程需要等讀文件的線程執行完才可以執行,如果還有在讀的線程則寫線程需要等待。
理一理讀者優先的互斥關系
1)當寫文件的時候其他線程都不能訪問,那么程序怎么知道有沒有寫線程在執行呢?所以需要一個信號量WriteMutex來記錄允許同時寫文件的線程數,即初始值(最大值)為1的信號量,同時也是互斥量、鎖。當讀和寫線程的時候都需要檢查WriteMutex的值。??WriteMutex保證了寫-寫和讀-寫互斥
Writer(){wait(WriteMutex); //WriteMutex減1 write ....post(WriteMutex); //WriteMutex加1 }Reader(){wait(WriteMutex); write ....post(WriteMutex); }2)在步驟一實現的條件,下如何實現讀者優先呢? 如果WriteMutex檢查通過,意味著沒有寫任務,接下來執行的應全是讀任務。需要思考的是,當有n的讀線程隊列有執行權時,此時來了一個寫線程,怎么保證這n個讀線程能夠控制住?WriteMutex 不大于0 呢?
3) 讀-讀被允許,上述寫法無法支持多個讀線程并行。因為WriteMutex的最大值為1,被 wait() 一次值就為0了,再wait就阻塞了。如何支持多個讀線程并行呢?只需要第一個讀線程?wait(WriteMutex),最后一個讀線程post(WriteMutex) 就可以。那么需要一個整形的 Rcount 變量來記錄正在執行讀操作的線程個數。Rcount是共享變量,且大于1。所有值可能大于1的共享變量都需要有一個互斥變量(鎖),來保證訪問改共享變量的互斥性。?所以Rcount需要一個互斥變量CountMutex ,具體的互斥操作就是,訪問Rcount時,利用CountMutex將Rcount “包”起來。
Writer(){wait(WriteMutex); //WriteMutex減1 write ....post(WriteMutex); //WriteMutex加1 }Reader(){wait(CountMutex); // 每次訪問Rcount前都要保證互斥if(Rcount == 0 ) //沒有在執行的讀線程,意味著當前時讀線程隊列的第一個wait(WriteMutex); // 第一個讀線程保證不允許寫操作。Rcount ++;post(CountMutex); // 訪問完Rcount就要釋放訪問權read ....wait(CountMutex); Rcount --;if(Rcount == 0 ) //沒有在執行的讀線程,意味著當前時讀線程隊列的最后一個post(WriteMutex);post(CountMutex);}二、寫者優先
? ? ?當寫者優先時,讀文件的線程需要等寫文件的線程執行完才可以執行,如果還有在寫任務則讀線程需要等待。
? ? ?我們也理一理寫者優先的互斥關系。上述的讀者優先用信號量的方式實現。那么這次寫著優先,打算用Hansen Style管程的方式實現。
? ? 回想一下管程數據結構有啥?既然是管程那么就需要條件變量和管程鎖,還有資源變量,還有等待訪問管程的線程隊列。?管程鎖保證了最多只有1個線程在管程中執行。條件變量中包含了需要進行相應操作的阻塞隊列和阻塞線程數。執行條件變量wait時,會釋放管程鎖,讓線程進入阻塞態。如果被喚醒,那么再獲取管程鎖繼續執行。執行條件變量signal時,會把阻塞線程隊列喚醒1個線程。執行條件變量brocase
?
1)讀寫者問題中有兩種類型的操作,一個是讀操作和另一個寫操作。所以條件變量需要兩個,okToRead和okToWrite 來記錄被阻塞的讀線程和寫線程數。一個管程只需要1個管程鎖。那么條件變量 和??緩存區鎖的設計可以了,資源變量又有什么呢?
已知阻塞寫線程有 n 和?阻塞讀線程有 m個。
2)當有寫線程進入臨界區時,其他線程不可以進入臨界區。所以需要資源變量AW來記錄在臨界區的寫文件的線程數,即初始值為0,最大值為1。當寫線程退出臨界區時,喚醒1個寫線程,如果沒有等待的寫線程,則喚醒所有阻塞的讀線程。所以需要有WR來記錄被阻塞的讀線程數,WW記錄被阻塞的寫線程數。
3)? 允許有 m 個讀線程同時進入臨界區并于寫線程互斥,那么就要像上面讀者優先一樣,用一個資源變量AR來記錄在臨界區的讀文件的線程數。當中間有寫線程待訪問時必須等所有讀線程都退出臨界區才行
數據結構如下:
對于讀操作:
1)獲取管程鎖后,利用AW和WW判斷是否有正在寫和等待寫的任務,如果有則將自己阻塞到等待讀隊列中,并修改WR值
2)保證了不存在寫線程,那么就進入臨界區,AR ++ ,讀共享資源。沒有給read database 加鎖,意味著所有的讀線程都可以同時處于臨界區中。
3)當訪問完臨界區,AR--時,利用AR 和 AW 判斷,如果所有讀線程都退出臨界區,且存在阻塞的寫線程時才喚醒寫線程。
?
對于寫操作:
1)獲取管程鎖后,利用AW和AR判斷是否有正在寫和正在讀的任務,如果有則將自己阻塞到等待寫隊列中,并修改WW值。
2)保證了只有自己一個線程處于執行態,那么就進入臨界區,AW ++ ,寫共享資源。雖然沒有給write database 加鎖,但是前面保證了只有1個寫線程可進入臨界區就不需要加鎖了。
3)當訪問完臨界區,AW--時,如果有等待的寫線程就喚醒1個,沒有等待的寫線程就喚醒所有等待的讀線程。
?
?
?
?
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的操作系统原理:读写者经典同步问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux C: 为什么C都必须有一个m
- 下一篇: 操作系统原理:死锁的特征,预防,避免,恢