Linux下進程間通信概述
Linux下的進程通信基本上是從UNIX平台上的進程通信繼承來的。而對UNIX發展做出最大貢獻的倆大主力AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟件發布中心)在進程的通信方面的側重點有所不同。前者是對UNIX早期的進程間通信手段進行了系統的改進和擴充,形成了“System V IPC”,其通信主要局限在單個計算機內;后者跳出了該限制,形成了基於套接字(Socket)的進程間通信機制。而Linux則把兩者的優勢都繼承下來。
LINUX 進程間通信方式:
傳統: /* 通用級 */
有名管道:mkfifo write read close
無名管道:pipe write read close
信號:signal kill raise pause alarm
POSIX:/* 新的、輕量級 */
信號量: man sem_overview
有名:sem_open sem_close sem_unlink
無名:sem_init sem_destroy
sem_post sem_wait sem_getvalue
共享內存: man shm_overview
shm_open shm_unlink mmap munmap
消息隊列: man mq_overview
mq_open mq_close mq_unlink mq_send mq_receive
system V:/* 古老的、重量級 */
信號量集:
semget semctl semop
共享內存:
shmget shmctl shmat shmop
消息隊列:
msgget msgop msgctl msgsnd msgrcv
BSD:
Socket通信
連接:
SERVER: socket bind listen accept recv send
CLIENT: socket bind connect send recv
無連接:
SERVER: socket bind recvfrom sendto
CLIENT: socket bind sendto recvfrom
在Linux中使用的進程間通信(IPC)方式
管道(Pipe)及有名管道(命名管道)(Named Pipe):管道可以用於具有親緣關系的進程進行通信。有名管道除了具有管道的所有功能外,還允許無情緣關系的進程間通信。
信號(Signal):信號實在軟件層次上的對中斷機制的一種模擬,它是比較復雜的通信方式,用於通知進程有某事件發生,一個進程收到一個信號與處理機收到一個中斷請求效果上可以說是一樣的。信號也是唯一一種進程間異步通信的方式,雙方在通信前不用先做好准備。
消息隊列(Message Queue):消息隊列是消息的鏈接表,包括POSIX消息隊列和System V消息隊列,它克服了前兩種消息量有限的缺點,並按照權限進行操作消息隊列。
共享內存(Shared Memory):共享內存是最高效的進程間通信方式。它使得多個進程可以使用同一塊內存空間。但這種通信方式需要依靠某種同步機制,如互斥鎖、信號量來保證安全性。
信號量(Semaphore):主要用於進程(線程)間的同步和互斥通信。
套接字(Socket):這是一種應用范圍更廣的進程間通信方式。它不僅可以在本地進程間通信,還可以用於不同主機內進程通信。
管道通信
無名管道
它只能用於有親緣關系(父子,兄弟等)的進程間的通信。
它是一個半雙工的通信模式,具有固定的讀端和寫端。
管道可以看成特殊的文件,對它的操作可以使用read和write,它不屬於任何文件系統,存在於內存中。
有名管道(命名管道)
它可以實現不相關的兩個進程間彼此通信。
命令管道FIFO嚴格按照先進先出的規則。不支持lseek操作。
命名管道在文件系統中是可見的,使用mkfifo可以創建該類型文件
常用函數
pipe,read,write,mkfifo
注意事項
int pipe(int fd[2]),下標為0的為讀端,下標為1的為寫端
只有在讀端存在的時候寫入才有意義,否則,向管道寫入數據的進程將收到SIGPIPE信號,進程被殺死。
信號
信號是在軟件層次上對中斷機制的一種模擬,信號是異步的,一個進程不必通過任何操作來等待信號到來,即進程處於未執行的狀態,內核會保存其信號,待進程執行時在傳給它。最常用的發送信號的系統函數有kill(),raise(),alarm(),setitimer()和sigqueue()等。
進程可以通過三種方式響應一個信號
忽略信號
忽略信號即對信號不做任何處理,其中SIGKILL和SIGSTOP不能被忽略。
執行默認操作
Linux對每種信號都有默認的處理,使用該方式進行處理信號。
捕捉信號
使用signal()函數注冊信號處理函數,在信號來時執行預定的處理函數。
常用函數
發送信號的函數:kill(),raise()
捕捉信號的函數:alarm(),pause()
注冊信號處理的函數:signal(),sigaction()
消息隊列
消息隊列就是一些消息的列表,用戶可以在消息隊列中添加小寫和讀取消息等。從這點上看,消息隊列具有FIFO的特性,但是它可實現消息的隨機查詢,比FIFO具有更大的優勢,同時這些消息存在於內核中,有隊列ID來標識。使用ipcs -q查看當前系統的消息隊列狀態。
常用函數
ftok() 獲取key
msgget() 獲取消息隊列id
msgsnd() 向消息隊列發送消息
msgrcv() 從消息隊列接收消息
msgctl() msg通用控制函數
共享內存
為了在多個進程間交換信息,內核專門流出了一塊內存區,這塊內存可以由需要訪問的進程映射到自己的私有地址空間,從而進程可以直接讀寫這一段內存,不需要復制數據。因此共享內存是最為高效的進程間通信方式。使用ipcs -m查看當前系統中共享內存使用狀態。
常用函數
ftok() 獲得key
shmget() 獲得共享內存id
shmat() 映射共享內存
shmdt() 取消映射共享內存
shmctl() 共享內存控制函數
信號量
背景:
在多任務的操作系統下,進程間可能存在一定的制約關系。例如間接制約和直接制約。
互斥關系
間接制約指進程間相互爭奪共享資源的關系,例如進程爭奪CPU時間片、I/O設備。
我們把進程間爭奪共享資源的關系稱為互斥關系。
同步關系
直接制約指進程間相互合作的關系,即需要按條件有固定順序的訪問某資源。例如讀者與寫者問題,進程A的輸出結果,進程B需要用到,所以進程B必須先等進程A完成。
我們把進程間有固定順序的操作某些資源的合作關系稱為同步關系。
對於同步與互斥的關系我們可以理解為:
同步關系包含互斥關系,互斥關系是一種特殊的同步關系。
同步與互斥的根本原因在於資源不足,共享資源。這些共享的資源被稱為臨界資源,這些操作臨界資源的代碼稱為臨界區。
信號量:
信號量是用來解決進程間同步與互斥問題的一種進程間通信機制,包括一個稱為信號量的變量和在該信號量下等待的資源的進程等待隊列,以及信號量進行的兩個原子操作(PV操作),其中信號量對應某一種資源,取一個非負整數。信號量的值指當前可用該資源的數量,若為0表示該資源當前沒有可用資源。
多個信號量又被稱為信號燈集。
PV原子操作的具體定義如下
P操作
如果有可用資源(信號量值>0),則占用一個資源(給當前信號量值減一,進入臨界區代碼);如果當前沒有可用資源(信號量值=0),則進程被阻塞直到系統將資源分配給該進程(進入等待隊列,直到資源輪到該進程使用)。
V操作
如果在該信號的等待隊列中有進程在等待資源,則喚醒一個阻塞進程;如果沒有進程等待該資源,則釋放一個資源(給當前信號量值加一)。
常用函數
ftok() 獲取key
semget() 獲取信號燈集ID
semop() 對信號燈集操作
semctl() 信號燈集的控制函數
sem_wait() 對信號量進行P操作sem_post() 對信號量進行V操作使用ipcs -s查看當前系統信號量使用情況。