
作者 良許 一個熱愛技術(shù)的程序猿
管道,又名「無名管理」,或「匿名管道」,管道是一種非?;?,也是使用非常頻繁的IPC方式。
1.1 管道本質(zhì)
管道的本質(zhì)也是一種文件,不過是偽文件,實際上是一塊內(nèi)核緩沖區(qū),大小4K; 管道創(chuàng)建以后會產(chǎn)生兩個文件描述符,一個是讀端,另一個是寫端; 管道里的數(shù)據(jù)只能從寫端被寫入,從讀端被讀出;
1.2 管道原理
管道是內(nèi)核的一塊緩沖區(qū),更具體一些,是一個環(huán)形隊列。數(shù)據(jù)從隊列的一端寫入數(shù)據(jù),另一端讀出,如下圖示:

1.3 管道的優(yōu)點
簡單
1.4 管道的缺點
管道創(chuàng)建三步曲: a. 父進程調(diào)用pipe函數(shù)創(chuàng)建管道; b. 父進程調(diào)用fork函數(shù)創(chuàng)建子進程; c. 父進程關(guān)閉fd[0],子進程關(guān)閉fd[1];
具體如下圖所示:

a. 管道的緩沖區(qū)大小固定為4k,所以如果管道內(nèi)數(shù)據(jù)已經(jīng)寫滿,則無法再寫入數(shù)據(jù),進程的write調(diào)用將阻塞,直到有足夠的空間再寫入數(shù)據(jù);
b. 管道的讀動作比寫動作要快,數(shù)據(jù)一旦被讀走了,管道將釋放相應(yīng)的空間,以便后續(xù)數(shù)據(jù)的寫入。當所有的數(shù)據(jù)都讀完之后,進程的read()調(diào)用將阻塞,直到有數(shù)據(jù)再次寫入。
父子間通信:
1#include 2#include 3#include 4#include 5 6int main() 7{ 8 int fd[2]; 9 pid_t pid; 10 char buf[1024]; 11 char *data = 'hello world!'; 12 13 /* 創(chuàng)建管道 */ 14 if (pipe(fd) == -1) { 15 printf('ERROR: pipe create failed!\n'); 16 return -1; 17 } 18 19 pid = fork(); 20 if (pid == 0) { 21 /* 子進程 */ 22 close(fd[1]); // 子進程讀取數(shù)據(jù),關(guān)閉寫端 23 read(fd[0], buf, sizeof(buf)); // 從管道讀數(shù)據(jù) 24 printf('child process read: %s\n', buf); 25 close(fd[0]); 26 } else if (pid > 0) { 27 /* 父進程 */ 28 close(fd[0]); //父進程寫數(shù)據(jù),關(guān)閉讀端 29 write(fd[1], data, strlen(data)); // 向管道寫數(shù)據(jù) 30 printf('parent process write: %s\n', data); 31 close(fd[1]); 32 } 33 34 return 0; 35}
兄弟間通信:
1#include 2#include 3#include 4#include 5#include 6 7int main () 8{ 9 int fd[2]; 10 int i = 0; 11 pid_t pid; 12 char buf[1024]; 13 char *data = 'hello world!'; 14 15 /* 創(chuàng)建管道 */ 16 if (pipe(fd) == -1) { 17 printf('ERROR: pipe create failed!\n'); 18 return -1; 19 } 20 21 for (i = 0; i <>2; i++) { 22 pid = fork(); 23 if (pid == -1) { 24 printf('ERROR: fork error!\n'); 25 return -1; 26 } else if (pid == 0) { 27 break; 28 } 29 } 30 31 /* 通過i來判斷創(chuàng)建的子進程及父進程 */ 32 if (i == 0) { 33 /* 第一個子進程,兄進程 */ 34 close(fd[0]); // 兄進程向弟進程寫數(shù)據(jù),關(guān)閉讀端 35 write(fd[1], data, strlen(data)); 36 printf('elder brother send: %s\n', data); 37 close(fd[1]); 38 } else if (i == 1) { 39 /* 第二個子進程,弟進程 */ 40 close(fd[1]); 41 read(fd[0], buf, sizeof(buf)); 42 printf('younger brother receive: %s\n', buf); 43 close(fd[0]); 44 } else { 45 /* 父進程 */ 46 close(fd[0]); 47 close(fd[1]); 48 for (i = 0; i <>2; i++) { 49 wait(NULL); 50 } 51 } 52 53 return 0; 54}
|