# 管道,第 1 部分:管道介紹
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Pipes%2C-Part-1%3A-Introduction-to-pipes>
## 什么是 IPC?
進程間通信是一個進程與另一個進程通信的任何方式。你已經看過這種虛擬內存的一種形式了!一段虛擬內存可以在父母和孩子之間共享,從而實現通信。您可能希望將該內存包裝在`pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);`互斥鎖(或進程寬互斥鎖)中以防止競爭條件。
有更多標準的 IPC 方式,比如管道!考慮您是否在終端中鍵入以下內容
```source-shell
$ ls -1 | cut -d'.' -f1 | uniq | sort | tee dir_contents
```
以下代碼的作用是什么(如果你愿意,你可以跳過這個并不重要)?那么它`ls`是當前目錄(-1 表示它每行輸出一個條目)。然后`cut`命令在第一個周期之前獲取所有內容。 Uniq 確保所有行都是 uniq,排序將它們和 tee 輸出排序到文件。
重要的是,bash 創建 **5 個獨立的進程**,并將它們的標準出口/標準連接到管道,其中的跟蹤看起來像這樣。
(0)ls(1)------&gt;(0)cut(1)-------&gt;(0)uniq(1)------&gt;(0)排序(1)------&gt;(0)tee(1)
管道中的數字是每個進程的文件描述符,箭頭表示重定向或管道輸出的位置。
## 什么是管道?
POSIX 管道幾乎就像它的真正對應物 - 你可以在一端填充字節,它們將以相同的順序出現在另一端。然而,與真實管道不同,進程始終在同一方向,一個文件描述符用于讀取,另一個文件描述符用于寫入。 `pipe`系統調用用于創建管道。
```c
int filedes[2];
pipe (filedes);
printf("read from %d, write to %d\n", filedes[0], filedes[1]);
```
這些文件描述符可以與`read`一起使用 -
```c
// To read...
char buffer[80];
int bytesread = read(filedes[0], buffer, sizeof(buffer));
```
和`write` -
```c
write(filedes[1], "Go!", 4);
```
## 如何使用管道與子進程通信?
使用管道的常用方法是在分叉之前創建管道。
```c
int filedes[2];
pipe (filedes);
pid_t child = fork();
if (child > 0) { /* I must be the parent */
char buffer[80];
int bytesread = read(filedes[0], buffer, sizeof(buffer));
// do something with the bytes read
}
```
然后,孩子可以將消息發送回父母:
```c
if (child == 0) {
write(filedes[1], "done", 4);
}
```
## 我可以在一個過程中使用管道嗎?
簡短回答:是的,但我不確定你為什么要大聲笑!
這是一個向自己發送消息的示例程序:
```c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int fh[2];
pipe(fh);
FILE *reader = fdopen(fh[0], "r");
FILE *writer = fdopen(fh[1], "w");
// Hurrah now I can use printf rather than using low-level read() write()
printf("Writing...\n");
fprintf(writer,"%d %d %d\n", 10, 20, 30);
fflush(writer);
printf("Reading...\n");
int results[3];
int ok = fscanf(reader,"%d %d %d", results, results + 1, results + 2);
printf("%d values parsed: %d %d %d\n", ok, results[0], results[1], results[2]);
return 0;
}
```
以這種方式使用管道的問題是寫入管道可能阻塞,即管道僅具有有限的緩沖容量。如果管道已滿,寫入過程將阻止!緩沖區的最大大小取決于系統;典型值從 4KB 到 128KB。
```c
int main() {
int fh[2];
pipe(fh);
int b = 0;
#define MESG "..............................."
while(1) {
printf("%d\n",b);
write(fh[1], MESG, sizeof(MESG))
b+=sizeof(MESG);
}
return 0;
}
```
參見[管道,第 2 部分:管道編程秘密](/angrave/SystemProgramming/wiki/Pipes%2C-Part-2%3A-Pipe-programming-secrets)
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話