進程,線程通訊與同步1.0
Linux進程間通訊
- 管道/FIFO:管道中還有具名管道和非具名管道(即匿名管道)之分,非具名管道(即匿名管道)只能用於父子進程通訊,具名管道可用於非父子進程,具名管道就是FIFO,管道是先進先出的通訊方式
- 訊息佇列:訊息佇列是用於兩個進程之間的通訊,首先在一個進程中建立一個訊息佇列,然後再往訊息佇列中寫資料,而另一個進程則從那個訊息佇列中取資料. 需要注意的是,訊息佇列是用建立檔案的方式建立的,如果一個進程向某個訊息佇列中寫入了資料之後,另一個進程並沒有取出資料,即使向訊息佇列中寫資料的進程已經結束,儲存在訊息佇列中的資料並沒有消失,也就是說下次再從這個訊息佇列讀資料的時候,就是上次的資料!!!!
- 訊號量:訊號量,它與WINDOWS下的訊號量是一樣的,所以就不用多說了
- 共用記憶體:共用記憶體,類似於WINDOWS下的DLL中的共用變數,但LINUX下的共用記憶體區不需要像DLL這樣的東西,只要首先建立一個共用記憶體區,其它進程按照一定的步驟就能訪問到這個共用記憶體區中的資料,當然可讀可寫
- 訊號:signal
- 通訊端socket
IPC比較
1.管道:速度慢,容量有限,只有父子進程能通訊
2.FIFO:任何進程間都能通訊,但速度慢
3.訊息佇列:容量受到系統限制,且要注意第一次讀的時候,要考慮上一次沒有讀完資料的問題
4.訊號量:不能傳遞複雜訊息,只能用來同步
5.共用記憶體:能夠很容易控制容量,速度快,但要保持同步,比如一個進程在寫的時候,另一個進程要注意讀寫的問題,相當於線程中的安全執行緒(全域變數和靜態變數引起),當然,共用記憶體區同樣可以用作線程間通訊,不過沒這個必要,線程間本來就已經共用了同一進程內的一塊記憶體
2.0 線程同步方法
- 臨界區:通過對多線程序列化來訪問公用資源或一段代碼,速度快,適合控制資料訪問
- 互斥量:為協調共同對一個共用資源的單獨訪問而設計的.
- 訊號量:為控制一個具有有限數量使用者資源而設計.
- 事件對象:用來通知線程有一些事件已發生,從而啟動後繼任務的開始.
1、 事件對象(Event)
用事件(Event)來同步線程是最具彈性的了. 一個事件有兩種狀態:激髮狀態和未激髮狀態. 也稱有訊號狀態和無訊號狀態. 事件又分兩種類型:手動重設事件和自動重設事件. 手動重設事件被設定為激髮狀態後,會喚醒所有等待的線程,而且一直保持為激髮狀態,直到程式重新把它設定為未激髮狀態. 自動重設事件被設定為激髮狀態後,會喚醒“一個”等待中的線程,然後自動回復為未激髮狀態. 所以用自動重設事件來同步兩個線程比較理想.
2、 臨界區(Critical Section)
使用臨界地區的第一個忠告就是不要長時間鎖住一份資源. 但進入臨界區後必須儘快地離開,釋放資源. 如果不釋放的話,會如何?答案是不會怎樣. 臨界地區的一個缺點就是:Critical Section不是一個核心對象,無法獲知進入臨界區的線程是生是死,如果進入臨界區的線程掛了,沒有釋放臨界資源,系統無法獲知,而且沒有辦法釋放該臨界資源. 這個缺點在互斥器(Mutex)中得到了彌補.
3、 互斥量(Mutex)
互斥器的功能和臨界地區很相似. 區別是:Mutex所花費的時間比Critical Section多的多,但是Mutex是核心對象(Event、Semaphore也是),可以跨進程使用,而且等待一個被鎖住的Mutex可以設定TIMEOUT,不會像Critical Section那樣無法得知臨界地區的情況,而一直死等.
4、 訊號量(Semaphore)
訊號量是最具曆史的同步機制. 訊號量是解決producer/consumer問題的關鍵要素.
3.0線程通訊
1.全域變數
進程中的線程間記憶體共用,這是比較常用的通訊方式和互動方式.
註:定義全域變數時最好使用volatile來定義,以防編譯器對此變數進行最佳化.
2.Message訊息機制
常用的Message通訊的介面主要有兩個:PostMessage和PostThreadMessage,
PostMessage為線程向主視窗發送訊息. 而PostThreadMessage是任意兩個線程之間的通訊介面.
3.事件對象(CEvent對象)
4.0同步與互斥比較
- 所謂同步,是指散步在不同進程之間的若干程式片斷,它們的運行必須嚴格按照規定的某種先後次序來運行,這種先後次序依賴於要完成的特定的任務.
- 所謂互斥,是指散布在不同進程之間的若干程式片斷,當某個進程運行其中一個程式片段時,其它進程就不能運行它們之中的任一程式片段,只能等到該進程運行完這個程式片段後才可以運行
5.0 死結
產生死結的原因(1)競爭資源
(2)進程推進順序不當產生死結的必要條件
(1)互斥條件:一個資源在一段時間內只能被一個進程所使用,具有排它性.
(2)請求和保持:一個進程在請求新資源而阻塞時,對已獲得資源又保持不放.
(3)不剝奪:進程已獲得的資源,在未使用完之前不能被剝奪,只能在使用完時由自己釋放.
(4)環路等待:在發生死結時,必然存在一個進程--資源的環形鏈. 即進程集合{P1,P2,...,Pn}中的P1正在等待P2佔用的資源,P2正在等待P3佔用的資源,...,Pn正在等待P1佔用的資源.