《深入理解Linux內核》 第十九章:深入理解 Linux 進程通信機制(Process Communication)
關鍵詞:IPC、信號、管道、FIFO、消息隊列、信號量、共享內存、套接字、內核對象、同步機制
一、進程通信概述
1.1 為什么需要進程通信
在 Linux 系統中,進程是資源隔離的基本單位,彼此間通常無法直接訪問彼此的地址空間。因此需要一套機制,使得多個進程之間可以:
- 交換數據;
- 同步行為;
- 發送通知;
- 共享資源。
這些功能由 Linux IPC(Inter-Process Communication)子系統實現。
1.2 IPC 分類
類型 | 描述 |
---|---|
信號 | 最基本的異步通知機制 |
管道/FIFO | 字節流通信機制,面向數據流 |
消息隊列 | 面向結構化消息,先進先出 |
信號量 | 同步與互斥,典型用于資源控制 |
共享內存 | 多進程映射同一段內存,效率最高 |
套接字 | 網絡與本地通信統一抽象,支持多協議 |
二、信號(Signal)
2.1 概述
信號是進程間最早被引入的通信機制,本質上是一個異步事件通知。
示例信號 | 描述 |
---|---|
SIGINT | 中斷(Ctrl+C) |
SIGTERM | 終止進程請求 |
SIGKILL | 無條件終止進程(不可捕獲) |
SIGCHLD | 子進程結束通知父進程 |
2.2 信號相關系統調用
kill(pid, sig)
:向指定進程或進程組發送信號;signal(sig, handler)
:設置信號處理函數;sigaction()
:更強大的信號控制;sigprocmask()
:阻塞/允許某些信號;sigqueue()
:帶參數的信號發送。
2.3 內核實現
- 每個進程結構
task_struct
中包含sigpending
和signal
字段; - 信號通過
do_signal()
派發; - 某些信號是不可忽略/不可屏蔽的(如
SIGKILL
); - Linux 通過實時信號(
SIGRTMIN
~SIGRTMAX
)支持有序隊列與附加參數。
三、管道與 FIFO
3.1 管道(pipe)
管道是最基本的 IPC 數據流機制,數據在兩個進程間以 FIFO 形式流動。
int pipe(int pipefd[2]); // pipefd[0]=read, pipefd[1]=write
特點:
- 半雙工(單向通信);
- 父子進程間常見用途;
- 基于內核中的
pipe_inode_info
結構實現; - 使用緩沖區環形隊列實現數據傳輸。
3.2 命名管道(FIFO)
可跨進程、不限于親緣關系:
mkfifo /tmp/myfifo
特點:
- 是一種特殊文件;
- 可在 shell 中使用
< /tmp/myfifo
、> /tmp/myfifo
。
3.3 內核實現
- 管道是內核中一種特殊的字符設備;
- 每個 pipe 被表示為一個 inode;
- 內核用
struct pipe_inode_info
管理緩沖區、讀寫端等。
四、消息隊列(Message Queues)
4.1 概述
消息隊列允許進程以“消息”為單位進行通信,每條消息是結構化數據(類型 + 數據內容)。
int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
4.2 內核數據結構
struct msg_queue {struct list_head q_messages;...
};
- 所有消息鏈入
q_messages
; - 支持按類型匹配接收;
- 消息大小有限制(
msgmax
)。
4.3 特點
- 支持異步發送、同步接收;
- 按優先級接收;
- 屬于 System V IPC 之一;
- 支持權限與 quota 控制。
五、信號量(Semaphores)
5.1 概述
信號量提供一種同步機制,用于控制多個進程對共享資源的訪問,支持阻塞和非阻塞操作。
int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, size_t nsops);
- 每個信號量集合由
semid
索引; semop()
支持加鎖/解鎖操作(P/V操作);- 使用計數表示資源狀態。
5.2 內核結構
struct sem_array {struct sem *sem_base;...
};
- Linux 信號量集支持原子操作;
- 支持 undo 機制,在進程終止時自動釋放資源;
- 屬于 System V IPC 范疇,現代內核中逐漸被 futex 和 pthread 替代。
六、共享內存(Shared Memory)
6.1 概述
多個進程將一段物理內存映射到各自虛擬地址空間,實現高效通信。
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
特點:
- 速度最快的 IPC;
- 通常配合信號量/互斥鎖使用;
- 屬于 System V IPC;
6.2 內核實現
- 使用
shmid_kernel
描述共享段; - 實質上是內核為各進程映射同一段物理頁;
- 頁表項被多個進程共享;
- 寫時復制(COW)策略在此無效。
七、套接字通信(Socket)
7.1 套接字種類
類型 | 描述 |
---|---|
UNIX 域套接字 | 僅限本機通信,文件系統路徑尋址 |
INET 套接字 | 網絡通信,使用 IP 與端口 |
STREAM | 面向連接,類似 TCP |
DGRAM | 無連接,類似 UDP |
7.2 創建通信過程
int socket(int domain, int type, int protocol);
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);
int connect(int sockfd, struct sockaddr *addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- socket 通信是最通用的進程通信方式;
- 在內核中通過
sock
結構表示; - 數據緩沖使用
sk_buff
結構管理。
八、Linux IPC 統一接口
Linux 提供 /proc/sysvipc/
系統接口與 ipcs
工具來統一查看 IPC 對象:
ipcs -m # 共享內存
ipcs -q # 消息隊列
ipcs -s # 信號量
可以使用 ipcrm
刪除對象。
九、IPC 命名空間與隔離(Namespace)
9.1 IPC Namespace
每個 IPC 對象(shm、sem、msg)都可以在命名空間中隔離,容器技術(如 Docker)廣泛使用。
- 創建 IPC namespace:
unshare --ipc
- 每個命名空間有獨立的 IPC 資源空間;
- 安全、穩定、互不干擾。
十、內核源碼參考路徑
文件路徑 | 作用描述 |
---|---|
kernel/signal.c | 信號實現與分發 |
ipc/msg.c | 消息隊列實現 |
ipc/sem.c | 信號量實現 |
ipc/shm.c | 共享內存實現 |
fs/pipe.c | 管道與 FIFO 實現 |
net/unix/af_unix.c | UNIX 域 socket 實現 |
include/linux/ipc_namespace.h | IPC 命名空間 |
include/linux/shm.h | 共享內存頭文件 |
十一、小結
- Linux 提供多種 IPC 機制,各有優缺點與適用場景;
- 信號適合簡單事件通知;
- 管道與 FIFO 適合流式數據傳輸;
- 消息隊列支持結構化數據傳遞;
- 信號量用于同步資源控制;
- 共享內存效率最高,但需額外同步手段;
- 套接字最通用,跨主機通信也適用;
- IPC 命名空間提升系統隔離性與安全性。