? ? ? ?通過管道來實現進程間的通信的方法很經典,因為多個進程共享3-4G中的內核,所以在內核中存在一個管道(緩沖區),然后進程通過連接管道的兩端從而實現通信。假如說我們現在有一根管道,我們從左端放入一個小球,那么它會從右端滾出來,那么如果我們同時向兩端都放入一個小球,那么就不可能實現交叉傳遞了,所以管道是半雙工通信(即雙方都可以發送信息,但是雙方不能同時發送信息),因此管道的兩端一端是讀端,一端是寫端。那么要實現兩個進程的同時讀寫操作,就需要用兩個管道。
? ? ? ?首先先來說一下pipe,這是一個匿名管道(為啥叫匿名呢,下面講命名管道的時候就知道了),實現方式是循環隊列,它只能用于有血緣關系的進程間通信。首先我們先來看一下pipe函數的原型:
#include <unistd.h> int pipe(int pipefd[2]);
? ? ? ?傳入的參數是一個大小為2的數組,然后就得到了兩個文件描述符pipefd[0]和pipefd[1],前者用來指向管道的讀端,后者用來指向寫端。用一個父子進程來舉例,如果要實現父子進程間的通信,在fork前就需要創建一個pipe管道,如果創建成功返回0,如果失敗返回-1并設置errno,由于子進程復制了父進程的PCB,所以子進程也有父進程的文件描述符表,因此父子進程的pipefd都指向了同一個pipe管道,然后我們要規定管道的傳輸方向,如果我們要求父寫子讀的話,我們就在父進程中close(pipefd[0]),在子進程中close(pipefd[1])就好了,創建好管道后我們通過write和read函數進行讀寫操作。
那么在使用pipe通信的時候可能會遇到以下的幾種情況:
1. 當讀管道時,如果管道中沒有數據,則會阻塞,直到管道另一端寫入數據。
? ? ? ? ? 2. 當寫管道時,如果管道中已經滿了,則會阻塞,直到管道另一端讀出數據(可見讀出數據時,管道中將不會保留該數據)。
? ? ? ? ? 3. 當管道寫端關閉時,讀端讀完管道內的數據時,如果再次去讀沒有數據的管道會返回0,相當于讀到了EOF。
? ? ? ? ? 4. 當管道讀端關閉時,如果寫端在寫入數據時,產生SIGPIPE信號,寫進程默認情況下會終止進程。
? ? ? ?下面以父子進程的例子,來寫一個程序來實現一下,代碼如下:
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <stdlib.h>#include <string.h>int main(void){ char buf[1024] = "Hello Childn"; char str[1024]; int fd[2]; if(pipe(fd) == -1){ perror("pipe"); exit(1); } pid_t pid = fork(); // 父寫子讀 0寫端 1讀端 if(pid > 0){ printf("parent pidn"); close(fd[0]); // 關閉讀端 sleep(5); write(fd[1], buf, strlen(buf)); // 在寫端寫入buf中的數據 wait(NULL); close(fd[1]); } else if(pid == 0){ close(fd[1]); // 關閉寫端 int len = read(fd[0], str, sizeof(str)); // 在讀端將數據讀到str write(STDOUT_FILENO, str, len); close(fd[0]); } else { perror("fork"); exit(1); } return 0;}
? ? ? ?運行結果如下:
parent pidHello Child
? ? ? ?我們可以用fpathconf來查看管道的緩沖區大小,通過傳入文件描述符和_PC_PIPE_BUF兩個參數來獲得一個long整型的值。代碼如下:
printf("%ldn", fpathconf(fd[0], _PC_PIPE_BUF));
? ? ? ?還有就是我們可以通過設置O_NONBLOCK參數來實現非阻塞的情況,也就是說當一個進程還沒有寫數據時,另一個讀進程就會阻塞在那里,那么如果設置了O_NONBLOCK參數,該進程就不會阻塞在那里,會返回-1,并設置errno為EAGAIN,可以用goto語句或者while循環實現,那么設置O_NONBLOCK使用fcntl函數。
? ? ? ?fifo用來創建一個命名管道,可以解決非血緣關系的進程間通信,它的底層的實現原理和匿名管道相同,只不過是生成了一個可見的管道文件。管道文件用mkfifo命令來創建,如下圖所示:
? ? ? ?這個管道文件連接一個在內核中的管道,那么這個管道文件對于所有的進程都是可見的,那么進程通過打開這個管道文件就可以通過管道文件所連接的管道來實現非血緣關系的進程間通信了。因為這個管道有一個所有進程都可以訪問到的管道文件,所以fifo叫做命名管道,那么同理,pipe就只能通過fork的方式來復制文件描述符表來共享管道,而其他的進程卻訪問不到,所以叫做匿名管道。
? ? ? ?下面也通過代碼,來簡單的實現一下fifo的效果,這里我提前用mkfifo的命令來創建了一個管道文件,當然也可以在代碼中使用mkfifo函數來創建,先來看一下寫操作的進程的代碼:
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>#include <string.h>#include <sys/stat.h>#include <fcntl.h>int main(int argc,char *argv[]){ if(argc < 2){ printf("run errorn"); exit(1); } char buf[1024] = "Hello, I'm Charlesn"; int fd = open(argv[1], O_WRONLY); if(fd == -1){ perror("open file"); exit(1); } write(fd, buf, strlen(buf)); close(fd); return 0;}
? ? ?下面是執行讀操作的代碼:
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>int main(int argc, char *argv[]){if(argc < 2){printf("run errorn");exit(1);}char buf[1024];int fd = open(argv[1], O_RDONLY);int len = read(fd, buf, sizeof(buf));write(STDOUT_FILENO, buf, len);close(fd);return 0;}
? ? ? ?然后我們開兩個終端去分別運行這兩個程序,我們先運行寫操作的程序,然后再運行讀操作的程序(當你運行寫操作的程序時會阻塞在write,當運行讀操作的程序時才會往下執行,這個就是上面所說的四種情況中的一種),最終結果如下:
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
12306火車票訂票流程?12306火車票訂票必須先下載12306官網,根據提示進行注冊,注冊成功后再進行見證驗證。驗證成功后就可以買票了。我們先登錄我們的注冊賬號12306,點擊首頁,輸入你的出發地和目的地,輸入出行日期,點擊查詢車票,你需要購買的車次的車票就會出現在頁面上。點擊您購買的列車的座位,添加乘客,然后點擊提交訂單。系統會自動為你的座位生成一張票單,然后跳轉到支付頁面,點擊立即支付,支...
電腦沒網怎么裝網卡驅動?電腦可以安裝網卡驅動程序時如何安裝?;t連接到互聯網的步驟如下:首先,我們需要安裝一個名為 "驅動程序向導 "對于沒有連接到互聯網的計算機。您可以使用連接到互聯網的電腦或手機來獲取該軟件,特別是對于可以訪問互聯網的電腦用戶,您可以通過搜索 "驅動程序向導 "并將其安裝在未連接到互聯網的計算機上。運行 "驅動程序向導 "非聯網計算機中的程序。這時程序會自動檢測電腦的非聯網狀態...
英文publisher什么意思?這不是一回事?!鞍l布者”是指發布者。Bookseller是指圖書銷售商publisher是一種高級的辦公軟件,可以進行文字處理并輸出PDFMicrosoft office publisher是publisher的全稱,是Microsoft發布的桌面出版應用程序。它通常被認為是一個入門級的桌面發布應用程序。它可以提供比Word更強大的頁面元素控制功能,但不如專業的頁面...