linux 进程间通信之pipe
?
在實際開發(fā)過程中,程序員必須讓擁有依賴關系的進程集協(xié)調,這樣才能達到進程的共同目標。?
每個進程各自有不同的用戶地址空間,任何一個進程的全局變量在另一個進程中都看不到,所以進程之間要交換數(shù)據(jù)必須通過內核,在內核中開辟一塊緩沖區(qū),進程1把數(shù)據(jù)從用戶空間拷到內核緩沖區(qū),進程2再從內核緩沖區(qū)把數(shù)據(jù)讀走,內核提供的這種機制稱為進程間通信(IPC,InterProcess Communication)。
管道是一種最基本的IPC機制,由pipe函數(shù)創(chuàng)建:
#include <unistd.h>int pipe(int filedes[2]);?
管道作用于有血緣關系的進程之間,即通過fork所創(chuàng)建的進程。?
調用pipe函數(shù)時在內核中開辟一塊緩沖區(qū)(稱為管道)用于通信,它有一個讀端一個寫端,然后通過filedes參數(shù)傳出給用戶程序兩個文件描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的寫端(很好記,就像0是標準輸入1是標準輸出一樣)。所以管道在用戶程序看起來就像一個打開的文件,通過read(filedes[0]);或者write(filedes[1]);向這個文件讀寫數(shù)據(jù)其實是在讀寫內核緩沖區(qū)。pipe函數(shù)調用成功返回0,調用失敗返回-1。?
所以可以按下面的步驟進行進程間的通信:
?
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h>int main(void) {int fd[2];char str[1024] = "hello it is a test\n";char buf[1024] = {0};pid_t pid;//fd[0]讀端//fd[1]寫端if(pipe(fd) < 0){perror("pipe");exit(1);}pid = fork();if(pid > 0){//父進程里,關閉父讀close(fd[0]);sleep(3);//通過這個sleep可以知道管道的讀是一個堵塞函數(shù)write(fd[1], str, strlen(str));//當管道滿的時候,再寫就會阻塞 wait(NULL);close(fd[1]);//用完管道要關閉讀端和寫端 }else if(pid == 0){int len = 0;//子進程里,關閉子寫close(fd[1]);len = read(fd[0], buf, sizeof(buf));write(STDOUT_FILENO, buf, len);close(fd[0]);//用完管道要關閉讀端和寫端 }else{perror("fork");exit(1);}return 0; }運行結果: 運行后過3秒輸出 hello it is a test?
所以使用管道會有一些限制:?
兩個進程通過一個管道只能實現(xiàn)單向通信,比如上面的例子,父進程寫子進程讀,如果有時候也需要子進程寫父進程讀,就必須另開一個管道。?
管道的讀寫端通過打開的文件描述符來傳遞,因此要通信的兩個進程必須從它們的公共祖先那里繼承管道文件描述符。上面的例子是父進程把文件描述符傳給子進程之后父子進程之間通信,也可以父進程fork兩次,把文件描述符傳給兩個子進程,然后兩個子進程之間通信,總之需要通過fork傳遞文件描述符使兩個進程都能訪問同一管道,它們才能通信。
使用管道需要注意以下4種特殊情況(假設都是阻塞I/O操作,沒有設置O_NONBLOCK標志):
以上情況具有普遍性,設計的時候需要注意。
?
管道的局限性
管道的主要局限性正體現(xiàn)在它的特點上:
- 只支持單向數(shù)據(jù)流;
- 只能用于具有親緣關系的進程之間;
- 沒有名字;
- 管道的緩沖區(qū)是有限的(管道制存在于內存中,在管道創(chuàng)建時,為緩沖區(qū)分配一個頁面大小);
- 管道所傳送的是無格式字節(jié)流,這就要求管道的讀出方和寫入方必須事先約定好數(shù)據(jù)的格式,比如多少字節(jié)算作一個消息(或命令、或記錄)等等;
注:阻塞管道, 使用fcntl函數(shù)設置O_NONBLOCK標志(fcntl的使用方法)?
舉例:
?
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h>int main(void) {int fd[2];char str[1024] = "hello it is a test\n";char buf[1024] = {0};pid_t pid;//fd[0]讀端//fd[1]寫端if(pipe(fd) < 0){perror("pipe");exit(1);}pid = fork();if(pid > 0){//父進程里,關閉父讀close(fd[0]);sleep(5);write(fd[1], str, strlen(str));//當管道滿的時候,再寫就會阻塞 wait(NULL);close(fd[1]);//用完管道要關閉讀端和寫端 }else if(pid == 0){int len = 0, flags;//子進程里,關閉子寫close(fd[1]);//使其非阻塞---------------------------------------flags = fcntl(fd[0],F_GETFL);flags |= O_NONBLOCK;fcntl(fd[0],F_SETFL,flags);while(1){len = read(fd[0], buf, sizeof(buf));if(len == -1){perror("read");}else{write(STDOUT_FILENO, buf, len);break;}sleep(1);}close(fd[0]);//用完管道要關閉讀端和寫端 }else{perror("fork");exit(1);}return 0; }運行結果: read: Resource temporarily unavailable read: Resource temporarily unavailable read: Resource temporarily unavailable read: Resource temporarily unavailable read: Resource temporarily unavailable hello it is a test?
轉載于:https://www.cnblogs.com/13224ACMer/p/6390351.html
總結
以上是生活随笔為你收集整理的linux 进程间通信之pipe的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#获取文件夹下的所有文件的文件名
- 下一篇: 前端含金量较高的网站推荐