一、管道
管道是進程間通信中最古老的方式,它包括 無名管道 和 有名管道兩種,前者用於父進程和子進程間的通信,后者用於運行於同一台機器上的任意兩個進程間的通信。 無名管道由pipe()函數創建。
#include <stdio.h>
#include <unistd.h>
#define INPUT 0
#define OUTPUT 1
int main()
{
int files[2];
pid_t pid;
char buf[256];
int returned_count;
//創建無名管道
pipe(files);
//創建子進程
if((pid = fork()) == -1)
{
perror("fork() error");
return -1;
}
//執行子進程
if(pid == 0)
{
printf("in child process....\n");
//子進程向父進程寫數據,關閉管道的讀端
close(files[INPUT]);
write(files[OUTPUT],"test data", strlen("test data"));
exit(0);
}
else
{
//執行父進程
printf("in the parent process...\n");
//父進程從管道中讀取子進程寫的數據,關閉管道的寫端
close(files[OUTPUT]);
returned_count = read(files[0], buf, sizeof(buf));
buf[returned_count] = '\0';
printf("%d bytes of data receiced from spawned process:%s\n", returned_count, buf);
}
return 0;
}
二、消息隊列
消息隊列用於運行於同一台機器上的進程間通信,它和管道很相似,是一個在系統內核中用來保存消息的隊列,它在系統內核中是以消息鏈表的形式出現。消息鏈表中節點的結構用msg聲明。
事實上,它是一種正逐步被淘汰的通信方式,我們可以用流管道或者套接口的方式來取代它。所以,我們對此方法也不再解釋,也建議讀者忽略這種方式。
三、共享內存
共享內存是運行在同一台機器上的進程間通信最快的方式,因為數據不需要在不同的進程間復制。通常由一個進程創建一塊共享內存區,其余進程對這塊內存區進行讀寫。得到共享內存有兩種方式:映射/dev/mem設備和內存映像文件。前一種方式不給系統帶來額外的開銷,但在現實中並不常用,因為它控制存取的將是實際的物理內存,在Linux系統下,這只有通過限制Linux系統存取的內存才可以做到,這當然不太實際。常用的方式是通過shmXXX函數族來實現利 用共享內存進行存儲的。 使用共享內存時要掌握的唯一訣竅是多個進程之間對一定存儲區d同步訪問。若服務器進程正在將數據放入共享內存,則在它做完這一操作之前,客戶進程不應當去讀取這些數據。 通常,信號量是用來實現對共享內存訪問的同步(記錄鎖也可以用於這種場合)。 使用共享存儲來實現進程間通信的注意點是對數據存取的同步,必須確保當一個進程去讀取數據時,它所想要的數據已經寫好了。通常,信號量被要來實現對共享存 儲數據存取的同步,另外,可以通過使用shmctl函數設置共享存儲內存的某些標志位如SHM_LOCK、SHM_UNLOCK等來實現。
四、信號
信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標准的信號函數sigaction(實際上,該函數是基於BSD的,BSD為了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數)。
五、信號量
信號量又稱為信號燈,它是用來協調不同進程間的數據對象的,而最主要的應用是前一節的共享內存方式的進程間通信。本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取狀況。一般說來,為了獲得共享資源,進程需要執行下列操作:
(1) 測試控制該資源的信號量。
(2) 若此信號量的值為正,則允許進行使用該資源。進程將信號量減1。
(3)若此信號量為0,則該資源目前不可用,進程進入睡眠狀態,直至信號量值大於0,進程被喚醒,轉入步驟(1)。
(4)當進程不再使用一個信號量控制的資源時,信號量值加1。如果此時有進程正在睡眠等待此信號量,則喚醒此進程。
維護信號量狀態的是Linux內核操作系統而不是用戶進程。我們可以從頭文件/usr/src/linux/include/linux/sem.h 中看到內核用來維護信號量狀態的各個結構的定義。信號量是一個數據集合,用戶可以單獨使用這一集合的每個元素。要調用的第一個函數是semget,用以獲得一個信號量ID。
六、套接口
套接口(socket)編程是實現Linux系統和其他大多數操作系統中進程間通信的主要方式之一。我們熟悉的WWW服務、FTP服務等都是基於套接口編程來實現的。除了異地的計算機進程間外,套接口同樣適用於本地同一台計算機內部的進程間通信。 關於這部分,可以參照《設計自己的網絡螞蟻》。那里由常用的幾個套接口函數的介紹和示例程序。
這一部分或許是Linux進程間通信編程中最須關注和最吸引人的一部分,畢竟,Internet 正在我們身邊以不可思議的速度發展着,如果一個程序員在設計編寫他下一個程序的時候,根本沒有考慮到網絡,考慮到Internet,那么,可以說,他的設計很難成功。