四、操作系统——读者写者问题(详解)
一、問題描述:
二、需要滿足的條件:
三、解題思路:
上面這種實現方式確實解決了了寫進程與寫進程之間必須互斥的寫入數據 和 寫進程與讀進程之間必須互斥的訪問共享數據 這兩個問題。但是,
假設讀進程A正在訪問共享數據,執行了P(rw) 和 讀數據操作,還沒有執行V操作解鎖,此時讀進程B也想訪問共享數據,此時,讀進程B會卡在P(rw)中的循環里面,也就是說進程B被阻塞了。
讀進程與讀進程之間也變成了必須互斥訪問共享數據,并不滿足題目讀進程與讀進程可以同時訪問共享數據的要求!
解決方法:
引入count變量,用來記錄當前有幾個讀進程在訪問共享數據。
上述實現方法表面上看達到了實現多個讀進程可以同時訪問共享數據的目的,但其實還是存在問題的。
存在的問題:
如果讀進程A想要訪問共享數據,并且執行了P(rw)“上鎖”操作,此時,讀進程B也想要訪問共享數據,也會執行P(rw),但是因為進程A已經執行了“上鎖”操作,所以進程B還是會被阻塞,無法訪問共享數據。可見,仍然沒有達到多個讀進程可以同時訪問共享數據的目的!
出現這種問題的原因:
對于count變量的檢查與賦值操作無法“一氣呵成”,可以被中斷。
解決方法:
可以增加一個mutex互斥信號量來保證if判斷語句 和 count++(count–) 能夠“一氣呵成”執行完,中間不會被打斷,保證各進程對count的訪問是互斥的。
上述解決方案確實已經達到了多個讀進程可以同時訪問共享數據的目的,但此時,又出現了新的問題:只要又讀進程在讀取共享數據,寫進程就要一直阻塞等待,這很可能導致寫進程一直無法往共享數據中寫入數據,也就是說寫進程很有可能會被“餓死”。因此,這種算法中,讀進程是優先的!下面我們來解決寫進程可能會被“餓死”這個問題
解決方法:
設置變量semaphore w =1 ,用于實現“寫優先”。然后分別為讀進程、寫進程增加關于信號變量w的P、V操作。
經過上面的“改造”,我們來驗證一下是否達到了“寫優先”的目的:
讀進程A——>寫進程a——>讀進程B:
假設讀進程A正在訪問共享數據,那么讀進程A肯定已經執行了P(w)、P(mutex)、P(rw)、V(mutex)、V(w)。此時,寫進程a也想要訪問共享數據,那么當讀進程a執行P(w)時,不會被阻塞,但是執行到P(rw)時,由于讀進程A還沒有執行V(rw)“解鎖”操作,所以,寫進程a會被阻塞等待。
而如果此時有第二個讀進程B也想要訪問共享數據,但由于之前第一個讀進程A已經執行了P(w)“上鎖”操作,所以當讀進程B執行到P(w)操作時,也會被堵塞等待。
直到讀進程A完成了讀文件操作后,執行了V(rw)“解鎖”操作,寫進程a才會被“喚醒”。然后在寫進程完成了寫文件操作后,執行了V(w)“解鎖”操作,讀進程B才能被喚醒。
注意:這里為什么會先喚醒寫進程a呢?
答:因為這里是寫進程a比讀進程B先想要訪問共享數據,所以優先被喚醒。這里其實就是“先來先服務算法”
結論:
在這種算法中,連續進入的多個讀進程,可以同時讀文件;寫進程和其他進程不能同時訪問文件;寫進程不會“饑餓”。但也并不是真正的“寫優先”,而是遵循相對公平的先來先服務原則。有的也稱這種算法為“讀寫公平法”。
四、總結:
讀者-寫者問題為我們解決復雜的互斥問題提供了一個參考思路:
其核心思想在于設置了一個計數器count用來記錄當前正在訪問共享文件的讀進程數。我們可以用count的值來判斷當前進入的進程是否是第一個/最后一個讀進程,從而做出不同的處理。如果是第一個進程則執行“上鎖”操作,如果是最后一個進程則執行“解鎖”操作。
另外,對count變量的檢查和賦值不能一氣呵成導致了一些錯誤,如果需要實現“一氣呵成”,自然應該想到用互斥信號量。
最后,還要認真體會我們是如何解決“寫進程饑餓”問題的。
絕大多數的PV操作大題都可以用之前介紹的幾種生產者-消費者問題的思想來解決,如果遇到更復雜的問題,可以想想能否用讀者寫者問題的這幾個思想來解決。
總結
以上是生活随笔為你收集整理的四、操作系统——读者写者问题(详解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS高级——JSON、数据存储学习笔记
- 下一篇: python如何读取字典的关键字_pyt