第19章 進程通信
1 管道
1.1 特點
- 生產者/消費者模型
- 半雙工:雙向,每次都能朝一個方向傳輸數據
- 管道作為一組VFS對象,可以使用VFS通用結構訪問(比如讀寫);管道被組織為pipefs這種特殊文件系統,在系統目錄樹沒有安裝點,用戶看不到它們
- 管道創建后,返回一對文件描述符,分別用來讀和寫;然后通過fork()系統調用把這對描述符傳給子進程,實現父子進程的管道通信
- 管道創建后,可以被任意進程使用,但是因為其半雙工工作模式,如果有多個進程對其訪問,必須加鎖
- 管道創建的系統調用為pipe(),C函數庫中,popen()和pclose()封裝了管道相關的系統調用,更加方便
1.2 典型應用
ls | grep xxx
“|”可以創建管道;第一個子進程ls的標準輸出被“|”重定向管道中;第二個子進程grep從管道讀取數據作為輸入,以替代標準輸入,完成grep操作;grep的輸出默認為標準輸出。
1.3 管道數據結構
管道也是文件,可以通過VFS系統調用來訪問管道,因此對于每個管道,應該有:一個索引節點對象 + 兩個文件對象(讀寫);
如果一個索引節點表示管道,其i_pipe成員指向struct pipe_inode_info結構:
- struct wait_queue *wait:管道/FIFO 等待隊列,里面是等待讀寫的進程
- struct pipe_buffer[] bufs:管道緩沖區描述符數組,里面包含寫入管道待讀出的數據
- unsigned int curbuf:待讀數據所在的緩沖區索引
- unsigned nrbufs:包含待讀數據的緩沖區數量,curbuf + nrbufs得到首個可寫緩沖區
1.4 從管道中讀數據
從一個管道中讀取n個字節(阻塞讀)
| 管道大小p | 有寫進程 | 無寫進程 |
| p = 0 | 等待數據直到拷貝n個字節,返回n | 返回0 |
| 0 < p < n | 等待數據直到拷貝n個字節,返回n | 拷貝p個字節并返回p,管道為空 |
| p >= n | 拷貝n個數據并返回n,管道還剩p-n個字節 | 拷貝n個數據并返回n,管道還剩p-n個字節 |
對于阻塞讀,如果管道為空 && 沒有寫進程,會返回已經拷貝的字節數,不會等待;
對于非阻塞讀,立刻拷貝并返回結果(拷貝的字節數),并不會關心有無寫進程。
1.5 向管道中寫數據
把n個字節寫入管道(阻塞寫)
| 可用緩沖區u | 有讀進程 | 無讀進程 |
| u <= n <= 4096 | 等待讀,直到有n-u個字節被釋放,才寫入n個字節,返回n | 發送SIGPIPE并返回-EPIPE |
| u >= n | 寫入n個字節,返回n | 寫入n個字節,返回n |
如果管道緩沖區大小不足,且沒有讀進程,直接返回。
2 FIFO(命名管道)
1.2 特點
- 生產者/消費者模型
- 與管道不同的是:FIFO具有文件名且包含在系統目錄樹中;是一種全雙工通信
- 因為存在文件名,所以可以被任意進程通過文件名訪問
3 System V IPC
- Interprocess Communication,進程間通信
- IPC資源包括信號量、消息隊列和共性內存,可以由任一進程訪問
- 統一使用IPC數據結構,進程請求IPC資源時創建IPC數據結構
關于共享內存:
- 最高效的進程通信形式
- 允許多個進程共享內存
- 進程訪問共享內存時,需要在自己的地址空間新增內存區,該內存區將與共享內存物理頁框映射
- shmat()函數把一個共享內存區attach到進程上,返回內存區起始線性地址;shmat()不修改進程的頁表
- 共享內存區缺省限制:最大數量4096,每個共享內存塊最大32MB,所有共享內存區的最大字節數8GB —— 這些限制可以調整
- 每個IPC共享內存區屬于shm特殊文件系統,在系統目錄樹沒有安裝點,因此用戶不能通過VFS打開訪問它的文件
4 POSIX消息隊列
IPC屬于內核提供給用戶進程的進程間通信方法,其中包括消息隊列;
POSIX消息隊列屬于基于POSIX標準接口的消息隊列,基于消息隊列實現,具有很多優點:
- 更簡單的基于文件的應用接口
- 完全支持消息優先級
- 完全支持消息到達的異步通知
- 完善的超時機制
5 套接字
- server-client模型
- 適用于不同計算機通過網絡交換數據
本文來自博客園,作者:moonのsun,轉載請注明原文鏈接:http://www.rzrgm.cn/moon-sun-blog/p/18842007

浙公網安備 33010602011771號