1. 程式人生 > >linux同步與通信

linux同步與通信

數據不一致 sha 能夠 屬性。 異常終止 內存拷貝 互斥鎖 協議 關聯

這幾天讀完了UNP v2,對進程間通信與同步的方式有所了解,現對主要的知識點總結如下:

根據出現的歷史,先有的管道,FIFO,信號,然後是systemV IPC,再是後來的Poxis IPC,systemV IPC是內核持續性的,而Poxis根據實現不同有的是內核有的是文件系統持續性。

管道:分為管道和FIFO, 管道一般用於父子進程,不能跨進程傳輸,FIFO可以在文件系統上建立對象,屬於一種文件類型(用p標識),可跨進程通信。他們的內容是進程持久性的,也就是說當進程結束時,管道中的內容都丟失了。管道一般都是單工的,只能單向通信,管道通信的前提是管道的兩端都被打開,不像消息隊列等打開一端就可以發送消息。管道傳輸的也是字節流,必要時需要制定應用層傳輸協議來防治粘包。

消息隊列:可以看做是一個消息鏈表,在某個進程往一個隊列中寫入消息之前,並不需要另外某個進程在該隊列上等待消息的到達。具有內核持續性,也就說一個進程寫入消息後可以中止,可讓另一個進程在以後某個時候讀出該消息。存放的是有邊界的消息記錄,每個消息含有優先級,POXIS消息隊列可以進行notify,在消息到達後通過信號或線程進行消息通知。SystemV消息隊列可以指定優先級,優先級高的被優先投遞,並支持接收指定優先級的消息。在編寫一對多模型的時候不同於管道需要創建多個連接,消息隊列只需要創建一個連接,各個進程都可以從其中標識地取出屬於自己的消息。缺點就是不能結合select/poll使用,必要時需要用管道轉接。新編寫的應用程序應該首先考慮使用POXIS消息隊列。

互斥鎖與條件變量: 可以實現生產者與消費者模型,可以動態分配也可以靜態分配,當動態分配並指定共享時可以用在進程間同步,存在的問題是當擁有互斥鎖的進程或線程異常終止時可能導致臨界區數據不一致。當某個進程阻塞在一個條件變量上的時候,如果調用pthread_exit/pthread_cancel取消線程時,會使該線程再次獲得該條件變量的互斥鎖,並且線程退出時並不會釋放該鎖,這樣就會造成死鎖,解決的辦法是使用pthread_cleanup_push/pthread_cleanup_pop來實現清理處理程序的安裝和刪除。

讀寫鎖: 可以提高並發度,根據實現的不同,可以分為讀優先,寫優先。讀寫鎖默認也是線程間的鎖,如果需要在進程間鎖也需要指定PTHREAD_PROCESS_SHARED 屬性。

記錄鎖: 可以提供細粒度的鎖,並且程序終止時會完成已有鎖的清理工作。由內核維護記錄鎖,分為建議性鎖和強制性鎖,強制性鎖可以阻止非協作進程讀一個已被鎖住的文件,但這並不能保證數據的一致性。

信號量: 分為有名信號量,基於內存的信號量,systemV信號量,Poxis有名信號量通過一個文件名打開,標識一個內核中文件系統的結構,所以是隨內核持久的,可以在進程間或線程間使用,而基於內存的信號量則具有隨進程的持續性。

相對於互斥鎖有三點不同:

1. 互斥鎖必須由給他上鎖的線程解鎖,信號量沒有這種限制;

2. 信號量有一個與之關聯的值,它由掛出操作加一,由等待操作減一,那麽任何線程都可以掛出一個信號,即使當時沒有線程在等待該信號量的值為正數也沒關系,但是如果某個線程調用pthread_cond_signal,但是沒有任何線程阻塞在pthread_cond_wait調用中,那麽相應條件變量的信號將丟失。

3. 各種同步技巧中能夠從信號處理程序中安全調用的唯一函數是sem_post函數。互斥鎖是為上鎖而優化的,條件變量是為等待而優化的,信號量即可用於上鎖又可用於等待,因而可能導致更多的開銷和更高的復雜性。

SystemV信號量則是計數信號量集,他維護一組信號量,他允許增長或減少信號量的值不只是1,所以相對posix信號量較為復雜。

共享內存區:共享內存區是IPC形式中最快的,一旦這樣的內存區映射到共享他的進程的地址空間,這些進程間數據的傳遞就不需要涉及內核(指不需要通過執行任何進入內核的系統調用),然而一般需要某種形式的同步。而管道,FIFO,消息隊列都需要經由內核傳遞,所以數據需要四次復制。

所有的共享方式都各有利弊吧,例如基於內核的有的需要內存拷貝,共享內存快卻需要加鎖來保障數據的一致性,所以我們應該按需使用。此外還有信號和socket,由於涉及內容太多,此處不再贅述。

linux同步與通信