首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

APUE 進程間通信(IPC)完整實戰:管道、FIFO、XSI IPC(消息隊列、信號量、共享記憶體)

     編輯:關於C語言

APUE 進程間通信(IPC)完整實戰:管道、FIFO、XSI IPC(消息隊列、信號量、共享記憶體)

本文為《Unix 環境高級編程》(APUE)學習筆記第十二篇,系統梳理 Unix/Linux 進程間通信機制:匿名管道、命名管道、System V IPC 三大組件(消息隊列、信號量、共享記憶體),並提供可編譯運行的完整 C 代碼範例。

一、管道

1. 特性

  • 半雙工:同一時間數據單向流動。
  • 固定讀端(pipefd[0])與寫端(pipefd[1])。
  • 自適應阻塞:寫滿阻塞寫者,讀空阻塞讀者。
  • 僅限親緣關系進程(父子、兄弟)。

2. pipe(2) 創建匿名管道

int pipe(int pipefd[2]); // 成功返回 0,pipefd[0] 讀端,pipefd[1] 寫端

3. 父子進程傳遞 "Hello!" 完整範例

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);
}

二、命名管道

1. mkfifo(3) 創建 FIFO 文件

int mkfifo(const char *pathname, mode_t mode); // 權限需 & umask
  • 磁盤上有實體文件,任意有權限進程可 open/read/write/close。
  • 無親緣關系限制,適合無關進程通信。

2. 兩個無關子進程雙向通信範例

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。

四、XSI IPC 概覽與管理命令

  • ipcs:查看共享記憶體、信號量、消息隊列狀態。
  • ipcrm:刪除殘留 IPC 對象。

三大組件均遵循 xxxget() 創建/獲取、xxxop() 操作、xxxctl() 控制/銷毀 命名規範。

五、XSI 消息隊列

1. 協議定義

struct msg_st {
    long mtype;       // 必須 > 0,消息類型
    char name[32];
    int math, chinese;
};

2. 核心函數

  • 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):銷毀。

3. 收發雙進程完整代碼

見原文 proto.h、rcver.c、snder.c,接收方先啟動創建隊列,發送方同 key 獲取並發送結構體。

六、XSI 信號量

1. 核心函數

  • semget(key, nsems, flags):創建信號量集,nsems=1 可模擬互斥鎖。
  • semctl(semid, semnum, cmd, ...):SETVAL 初始化值,IPC_RMID 刪除。
  • semop(semid, &sops, nsops):sem_op=-1 申請資源(P 操作),=1 釋放資源(V 操作)。

2. 20 進程並發遞增文件計數器(互斥鎖)

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(); }

七、XSI 共享記憶體

1. 核心函數

  • shmget(key, size, flags):創建段,返回 shmid。
  • shmat(shmid, NULL, 0):掛接到進程位址空間,返回指標。
  • shmdt(addr):分離。
  • shmctl(shmid, IPC_RMID, NULL):刪除(由創建者調用)。

2. 父子進程通信範例

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);

八、總結與選型建議

實際工程中常組合使用:共享記憶體 + 信號量/互斥鎖 實現高效同步數據交換。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
機制適用場景優點缺點
匿名管道親緣進程單向數據流簡單、自動同步無名、單向、無格式
命名管道無關進程單向/雙向文件介面、跨進程半雙工、需協議避免髒讀
消息隊列結構化數據、多類型消息帶類型、雙工、內核持久複製開銷、大小限制
信號量同步/互斥、資源計數原子操作、集合支援非數據傳輸、易死鎖
共享記憶體大量數據高速交換最快、無複製需自行同步、無結構