c语言管程例子,管程 - it610.com
一、信號量的缺點
信號量的使用一定要小心,如下圖中解決生產者-消費者問題的程序:
如果在producer的執行函數中,將empty與mutex的down操作互換,如果此時mutex為0,將首先對mutex進行down操作,進程陷入阻塞,而同時,當consumer的執行函數執行到down(&mutex)的時候,由于mutex為0,因此,consumer線程也將進入阻塞,兩個進程都將永遠進入阻塞狀態,這被稱為“死鎖”
這說明使用信號量時一定要非常小心,一處很小的錯誤將有可能導致很大的麻煩,因為競爭條件、死鎖以及其他一些問題都是不可預測和不可再現的行為
為了更易于編寫正確的程序,一種高級同步原語?--?管程(monitor)誕生了
二、管程
一個管程是一個由過程、變量及數據結構等組成的一個集合,它們組成一個特殊的模塊或軟件包。
管程內部的共享變量
管程內部的條件變量
管程內部并行執行的進程
對局部于管程內部的共享數據設置初始值的語句
進程可以在任何需要的時候調用管程中的過程,但是他們不能在管程之外聲明的過程中直接訪問管程內的數據結構
但是,需要注意的是管程是語言概念,而C語言并不支持它
任意時刻,管程中只能有一個活躍的進程,這一特性是的管程能夠有效地完成互斥,由編譯器選擇采取與其他過程調用不同的方法來處理對管程的調用
典型的處理方法是,當一個進程調用管程過程時,該過程中的前幾條指令將檢查在管程中是否有其他的活躍進程,如果有,調用進程將被掛起,知道另一個進程離開管程將其喚醒,如果沒有,則該調用進程可以進入
進入管程時的互斥由編譯器負責,但通常的做法是用一個互斥量或二元信號量,因為是有編譯器而非程序員來安排互斥,所以出錯的可能性要小得多
在任何一個時刻,寫管程的人無需關心編譯器是如何實現互斥的,他只需要知道將所有的臨界區轉換成管程過程即可,絕不會有兩個進程同時執行臨界區中的代碼。
三、管程中的條件變量
管程提供了一種實現互斥的漸變途徑,但是我們還需要一種辦法使得進程在無法繼續運行時被阻塞,解決這個問題的方法就是引入條件變量,以及相關的兩個操作:wait和signal,當一個管程過程發現他無法繼續運行時(如生產者發現緩沖區已滿),他會在某個條件變量上(如full)上執行wait操作,該操作導致調用進程自身阻塞,并將另一個等在管程外的進程調入管程,同時,一個進程也可以通過對伙伴正在等待的一個條件變量執行signal操作完成喚醒正在睡眠的伙伴進程,但是這個時候就有可能會出現兩個活躍進程同時處在管程中的情況,這個情況有兩種方案可以解決:
運行新喚醒的進程,掛起之前的進程
執行signal的進程立即退出管程,即規定signal只能作為管程過程的最后一條語句
讓發信者繼續運行直到發信者退出管程后才讓被喚醒的進程運行
很明顯,第一種方案更加簡單,所以一般我們采取這一方案
注意,條件變量與信號量不同,他并不是計數器,如果向一個條件變量發送信號,而這個條件變量上此時并沒有等待進程,則這個信號就會丟失,也就是說wait必須在signal之前執行
wait、signal與sleep、wakeup最大的區別是他們不存在嚴重的競爭條件,因為可能存在一種情況,即當一個進程正要去sleep而實際還沒有sleep的時候,另一個進程企圖喚醒他,從而造成了wakeup信號的丟失,而管程中不會存在這樣的問題,因為在緩沖區滿,生產者wait前,消費者進程根本不可能進入管程
四、代碼示例
如圖所示,是用管程實現生產者-消費者問題揭發框架的一個類似于pascal的偽代碼
java支持用戶級進程,只要將關鍵詞synchronized加入到方法聲明中,java就保證這個方法一旦被某個進程執行,就不允許其他進程執行它,因此我們可以通過這一特性實現管程的編程
這個例子其實并不難懂,由于有synchronized關鍵字,所以無論是producer要進行的insert方法還是consumer要進行的remove方法都只能讓一個進程進入,因此他們不需要再擔心競爭條件
java中并沒有條件變量,反之,java提供了兩個過程:wait和notify,與sleep和wakeup等價,但他們并不受競爭條件約束,而是通過異常機制實現對中斷情況的處理
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的c语言管程例子,管程 - it610.com的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《无名》领跑!兔年大年初一预售票房破亿
- 下一篇: 中国AI领域以逐渐赶超美国 论文数量和质