前言:
(硬核,看過絕對學到!)在上一篇博客不做人系列用了對話的方式,但是訪問量低得可憐,所以咋們還是認真的寫一篇硬核讀者寫者模型。如果你要考研的話,操作系統方面大概率會出這種類似的題目,那麼一起來學習吧。
在我們開始學習之前,我們需要知道一些基礎的知識:
一個數據文件或記錄可以被多個進程共享,我們把只要求讀該文件的進程稱爲“Reader進程”,其他進程則稱爲“Writer進程”。允許多個進程同時讀一個共享對象,因爲該讀操作不會使數據文件混亂。但不允許一個Writer進程和其它Reader進程或Writer進程同時訪問共享對象。因爲這種訪問必將引起混亂。所謂“讀者-寫者(Reader-Writer Problem)問題”是指保證一個Writer進程必須與其它進程互斥地訪問共享對象的同步問題。
小思考:
那麼我們要如何實現讀者寫者模型呢?如果你看過上一篇,那麼你肯定會想到要用信號互斥量的知識點,也就是用PV原語來進行限制。當時我們說的是在臨界資源前面加P(這裏P意味着申請資源,那麼記錄減一),後面加V(這裏V意味着釋放資源,記錄加一),所以我們也就有了第一種方案。
這裏怕大家忘記,給出PV語言(當然,也可以看上一篇哦,嘻嘻):
P原語wait(s)
--s.count;//表示申請一個資源
if(s.count<0)//表示沒有空閒資源;
{
調用進程進入等待隊列s.queue;
阻塞調用進程;
}
V原語signal(s)
++s.count;//表示釋放一個資源;
if(s.count<=0)//表示有進程處於阻塞狀態
{
從等待隊列中取出一個進程P;
進程P進入就緒隊列;
}
一、不成熟的方案
那麼上面拋出了問題之後,我們首先給出最簡單的方案,直接加PV原語:
P_Reader{//這裏我們設置互斥信號量爲mutex_Blackboard
*****************
P(mutex_Blackboard)
...
從黑板讀信息
...
V(mutex_Blackboard)
*****************
}
P_Writer{
*****************
P(mutex_Blackboard)
...
向黑板寫信息
...
V(mutex_Blackboard)
*****************
}
優點:
我們一看,寫者和寫者之間的確實現了互斥。
缺點:
1、來一個小例子:首先來了一個寫者,mutex_Blackboard減一,然後寫者開始操作,寫者操作完成了。又來了一個寫者,繼續操作,此時一旁的讀者,十分無奈,看!不做人了吧。
所以,我們要改進這個方法,那麼,既然讀是可以多個的,所以我們就讓讀者優先,這些讀者高興了吧,嘻嘻。
二、讀者優先方案
好的,所以我們就有了讀者優先的方案,在展示代碼之前,我們思考一下。怎麼樣纔可以實現讀者優先呢?
......動動腦子,嘻嘻嘻,越思考,越優秀!
這個時候,你可能會說,既然讀者優先的話,那麼我們只需要讓讀者佔有這個互斥信號量就好了呀。是的,在讀者塊上加一個PV原語,進行判斷:如果是第一個讀者,那麼就搶佔mutex_Blackboard,如果是第二個,第三個讀者,那麼我們先不釋放我們的mutex_Blackboard,直到最後一個讀者要走的時候,我們再釋放資源。這個時候寫者才能拿到資源,這不就是讀者優先了嗎?讀者多開心啊。
所以,描述如下:
P_Reader{
*****************
P(mutex_ReaderCount)//給讀者加互斥信號量mutex_ReaderCount
ReaderCount++//進來一個加一
if(ReaderCount==1)//如果是第一個,那麼就負責去和寫者強化mutex_Blackboard
P(mutex_Blackboard)
V(mutex_ReaderCount)
*****************
...
從黑板讀信息
...
*****************
P(mutex_ReaderCount)
ReaderCount--//如果是最後一個,把資源釋放了,給寫者(寫者真慘)
if(ReaderCount==0)
V(mutex_Blackboard)
V(mutex_ReaderCount)
*****************
}
P_Writer{
*****************
P(mutex_Blackboard)
...
向黑板寫信息
...
V(mutex_Blackboard)
*****************
}
優點:
的確讀者優先了,解決了上一個問題,多個讀者可以一起學習了(嘻嘻嘻)。
缺點:
來個小例子,來了一個讀者,開始操作,來了一個寫者,掛起等待,讀者走了,又來了一個讀者........來了100個讀者,寫者一直在等待。寫者說:“你們真的不是人,不行,我們要公平競爭!!!”。
三、讀者寫者公平競爭方案
所以,要公平競爭的話,我們要怎麼做呢?
......思考一下,越思考,越優秀啊
對!聰明的你又發現了,當讀者是第一個的時候,它會搶佔資源,然後下一個讀者來,又繼續佔有,這不行啊。所以你想起了上一篇博客的記錄者沒有,那麼我們這裏在讀者和寫者搶佔mutex_Blackboard的時候加一個信號互斥量,來一個PV原語。
所以,描述如下:
P_Reader{
*****************
P(mutex_Register)//加了一個記錄
P(mutex_ReaderCount)//給讀者加互斥信號量mutex_ReaderCount
ReaderCount++//進來一個加一
if(ReaderCount==1)//如果是第一個,那麼就負責去和寫者強化mutex_Blackboard
P(mutex_Blackboard)
V(mutex_ReaderCount)
V(mutex_Register)
*****************
...
從黑板讀信息
...
*****************
P(mutex_ReaderCount)
ReaderCount--//如果是最後一個,把資源釋放了,給寫者(寫者真慘)
if(ReaderCount==0)
V(mutex_Blackboard)
V(mutex_ReaderCount)
*****************
}
P_Writer{
*****************
P(mutex_Register)
P(mutex_Blackboard)
...
向黑板寫信息
...
V(mutex_Blackboard)
v(mutex_Register)
*****************
}
優點:
第一個讀者來了,register--,redercount--,人數加一,判斷是第一個,搶了Blackboard,釋放regiser,釋放redercount,讀操作......這個時候,來了一個寫者,regiser--,然後發現前面有人,那麼就掛起等待。這個時候,又來了一個讀者,前一個讀者完成了,就叫它的小弟上去插隊,讀者2上去,進行regiser判斷,發現前面有一個等待的,那麼不行,讀者2只好掛起等待。這個時候寫者就獲得資源,開始寫操作。一切多麼的公平啊!
但是,寫者說:“我們不及時更新消息,你們看啥呢???不行,我們要優先"!
四、寫者優先方案
好的,我們要讓寫者優先,你們想一想,要怎麼辦?
......動動腦子,嘻嘻嘻,越思考,越優秀!
是的,是的,你又想到了,沒錯,就是給讀者加之前寫者有些的PV判斷,但是這樣還不夠呀,我們要給讀者再加一個PV,讓他們比寫者多一個資源判斷,就繼續排隊呀。哈哈,不做人了!
描述如下:
P_Reader{
*****************
P(mutex_enhance)//再加一個,嘻嘻
P(mutex_Register)//加了一個記錄
P(mutex_ReaderCount)//給讀者加互斥信號量mutex_ReaderCount
ReaderCount++//進來一個加一
if(ReaderCount==1)//如果是第一個,那麼就負責去和寫者強化mutex_Blackboard
P(mutex_Blackboard)
V(mutex_ReaderCount)
V(mutex_Register)
V(mutex_enhance)
*****************
...
從黑板讀信息
...
*****************
P(mutex_ReaderCount)
ReaderCount--//如果是最後一個,把資源釋放了,給寫者(寫者真慘)
if(ReaderCount==0)
V(mutex_Blackboard)
V(mutex_ReaderCount)
*****************
}
P_Writer{
*****************
P(mutex_WriterCount)
WriterCount++
if(WriterCount==1)
P(mutex_Register)
V(mutex_WriterCount)
******************
P(mutex_Blackboard)
...
向黑板寫信息
...
V(mutex_Blackboard)
*****************
P(mutex_WriterCount)
WriterCount--
if(WriterCount==0)
V(mutex_Register)
V(mutex_WriterCount)
*****************
}
優點:
那麼來一遍,首先來了一個寫者,那麼進去,寫操作ing,來了一個讀者,沒有register等待。又來了一個寫者2,也是沒有Blackboard,等待。寫者1寫完了,交出了資源,這個時候讀者想要插隊,但是發現自己沒有enhance資源,只好繼續掛起。而寫者2則得到了資源,開始操作了。Oh,寫者不做人了呀。
缺點:
寫者不做人,嘻嘻。
五、小小變形demo
上面我們說了簡單的互斥,讀者優先,讀者寫者公平競爭,寫者優先,那麼看看掌握得怎麼樣了。
給出一個問題:
【問題】:讀者有兩個組別,讀者1組合讀者2組,讀者1組和讀者2組不會同時讀黑板,但同一組中的讀者可以同時讀黑板,並會插隊。
所以你會怎麼思考呢?小提示(不同時讀,那麼有互斥,可以同時讀,那麼可以組內優先)
所以給個參考答案吧:
P_Reader1 {
*****************
P(mutex_Reader1Count)
Reader1Count++
if(Reader1Count==1)
P(mutex_Blackboard)
V(mutex_Reader1Count)
*****************
...
從黑板讀信息
...
*****************
P(mutex_Reader1Count)
ReaderCount--
if(Reader1Count==0)
V(mutex_Blackboard)
V(mutex_Reader1Count)
*****************
}
P_Reader2 {
*****************
P(mutex_Reader2Count)
Reader2Count++
if(Reader2Count==1)
P(mutex_Blackboard)
V(mutex_Reader2Count)
*****************
...
從黑板讀信息
...
*****************
P(mutex_Reader2Count)
ReaderCount--
if(Reader2Count==0)
V(mutex_Blackboard)
V(mutex_Reader2Count)
*****************
}
真厲害,那麼我們在給出一個問題吧:
【問題】:讀者有兩個組別,讀者1組合讀者2組,讀者1組和讀者2組不會同時讀黑板,同一組中的讀者也不可以同時讀黑板,但可以插隊。
給出你的答案吧,下篇不做人系列我會給出參考答案哦,如果不怎麼有思路,可以試着轉換爲上面的讀寫這問題哦。
總結:
好的,關於互斥的操作,簡單過了一遍吧,那麼你肯定會想,有些時候我們會要求寫者在讀者前面對吧,這個時候就涉及到了同步問題,那麼我們下一篇不做人系列見吧,如有誤,歡迎指正哦,謝謝。
預知後事如何,請聽下回分解......