本文為《Unix 環境高級編程》(APUE)學習筆記第十二篇,系統梳理 Unix/Linux 進程間通信機制:匿名管道、命名管道、System V IPC 三大組件(消息隊列、信號量、共享記憶體),並提供可編譯運行的完整 C 代碼範例。
pipefd[0])與寫端(pipefd[1])。int pipe(int pipefd[2]); // 成功返回 0,pipefd[0] 讀端,pipefd[1] 寫端
int pd[2]; pipe(pd);
pid = fork();
if (pid == 0) { // 子進程讀
close(pd[1]);
read(pd[0], buf, BUFSIZE);
puts(buf);
close(pd[0]);
} else { // 父進程寫
close(pd[0]);
write(pd[1], "Hello!", 6);
close(pd[1]);
wait(NULL);
}
int mkfifo(const char *pathname, mode_t mode); // 權限需 & umask
open/read/write/close。mkfifo("/tmp/myfifo", 0644);
fork() 兩次創建 child1、child2,父進程退出使其無親緣關系。
child1: open(O_RDWR) → write("Hello") → sleep(1) → read() → remove()
child2: open(O_RDWR) → read() → write(" World!")
關鍵點:sleep(1) 確保對方讀走數據再寫入,避免讀到自己寫的「髒數據」。
單管道半雙工,需兩個管道:進程 A 讀管道 1 寫管道 2,進程 B 讀管道 2 寫管道 1。
ipcs:查看共享記憶體、信號量、消息隊列狀態。ipcrm:刪除殘留 IPC 對象。三大組件均遵循 xxxget() 創建/獲取、xxxop() 操作、xxxctl() 控制/銷毀 命名規範。
struct msg_st {
long mtype; // 必須 > 0,消息類型
char name[32];
int math, chinese;
};
msgget(key, IPC_CREAT|0600):創建/獲取隊列,key 由 ftok(path, proj) 生成。msgsnd(msqid, &msg, size, 0):發送。msgrcv(msqid, &msg, size, type, 0):接收,type=0 表先進先出。msgctl(msqid, IPC_RMID, NULL):銷毀。見原文 proto.h、rcver.c、snder.c,接收方先啟動創建隊列,發送方同 key 獲取並發送結構體。
semget(key, nsems, flags):創建信號量集,nsems=1 可模擬互斥鎖。semctl(semid, semnum, cmd, ...):SETVAL 初始化值,IPC_RMID 刪除。semop(semid, &sops, nsops):sem_op=-1 申請資源(P 操作),=1 釋放資源(V 操作)。semid = semget(IPC_PRIVATE, 1, 0600);
semctl(semid, 0, SETVAL, 1); // 初始化為 1
P() { semop(semid, &{0, -1, 0}, 1); }
V() { semop(semid, &{0, 1, 0}, 1); }
func_add() { P(); read-modify-write file; V(); }
shmget(key, size, flags):創建段,返回 shmid。shmat(shmid, NULL, 0):掛接到進程位址空間,返回指標。shmdt(addr):分離。shmctl(shmid, IPC_RMID, NULL):刪除(由創建者調用)。shmid = shmget(IPC_PRIVATE, 1024, 0600); fork(); child: str = shmat(shmid, NULL, 0); strcpy(str, "Hello!"); shmdt(str); parent: wait(); str = shmat(shmid, NULL, 0); puts(str); shmdt(str); shmctl(shmid, IPC_RMID, NULL);
| 機制 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 匿名管道 | 親緣進程單向數據流 | 簡單、自動同步 | 無名、單向、無格式 |
| 命名管道 | 無關進程單向/雙向 | 文件介面、跨進程 | 半雙工、需協議避免髒讀 |
| 消息隊列 | 結構化數據、多類型消息 | 帶類型、雙工、內核持久 | 複製開銷、大小限制 |
| 信號量 | 同步/互斥、資源計數 | 原子操作、集合支援 | 非數據傳輸、易死鎖 |
| 共享記憶體 | 大量數據高速交換 | 最快、無複製 | 需自行同步、無結構 |