进程间通信(IPC机制)——管道
1.管道的特點(diǎn)
(1)無論有名還是無名,寫入管道的數(shù)據(jù)都在內(nèi)存中。
(2)管道是一種半雙工通信方式(通信方式有單工(固定接收方發(fā)送方,接收方只能接收,發(fā)送方只能發(fā)送)、半雙工(如同對(duì)講機(jī),兩端可以切換寫入和接收)、全雙工(每端都可以接收和寫入,且可以同時(shí)進(jìn)行))。
(3)有名和無名管道的區(qū)別:有名可以在任意進(jìn)程間使用,而無名只能在父子進(jìn)程間。
(4)對(duì)于管道,我們只能以只讀打開或者只寫打開。
(5)有名管道得需要讀和寫都打開,否則只以讀打開或者只以寫打開都會(huì)阻塞。
(6)管道中沒有數(shù)據(jù)時(shí),讀管道read會(huì)發(fā)生阻塞,直至管道被寫入數(shù)據(jù),讀出數(shù)據(jù),再次阻塞。如果寫端被關(guān)閉,讀端read返回值會(huì)成為0。如果讀端被關(guān)閉,寫端向管道寫入數(shù)據(jù)后會(huì)自動(dòng)退出。
(7)管道寫滿后,寫端會(huì)阻塞。
(8)由于管道的數(shù)據(jù)都在內(nèi)存中,所以查看管道大小總是0。
管道的實(shí)現(xiàn):
寫入從頭指針開始,讀取從尾指針開始。寫入之后,頭指針挪動(dòng),讀取之后尾指針挪動(dòng)。如果是頭指針趕上尾指針,那么管道被寫滿,寫就會(huì)被阻塞。如果是尾指針趕上頭指針,那么管道為空,read阻塞。
管道可以用來在兩個(gè)進(jìn)程之間傳遞數(shù)據(jù),如: ps -ef | grep “bash”, 其中‘|’就是管道,其作用就是將 ps 命令的結(jié)果寫入管道文件,然后 grep 再從管道文件中讀出該數(shù)據(jù)進(jìn)行過濾。
管道大小是可以查看的,如下圖可以看到管道512字節(jié)為一個(gè)單位,乘以8就是整個(gè)管道大小。
2.有名管道
2.1有名管道的創(chuàng)建和頭文件
有名管道可以在任意兩個(gè)進(jìn)程之間通信
有名管道的創(chuàng)建:
(1)命令創(chuàng)建: mkfifo + 管道名
(2)系統(tǒng)調(diào)用創(chuàng)建
2.2有名管道的使用
進(jìn)程 a 從鍵盤獲取的數(shù)據(jù)循環(huán)傳遞給另一個(gè)進(jìn)程 b。
我們可以用創(chuàng)建一個(gè)文件,a從鍵盤獲取字符串存放到文件中,b從文件中讀取。但是文件是存在磁盤上的,速度沒有管道快,而且從文件讀不到數(shù)據(jù)不會(huì)等待,但是管道不一樣,b從管道讀不到數(shù)據(jù)會(huì)阻塞,直到a又向管道中寫入數(shù)據(jù)。
首先用命令mkfifo+管道名稱創(chuàng)建管道
寫端代碼:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<assert.h> #include<fcntl.h> #include<sys/stat.h>int main() {int fd = open("fifo",O_WRONLY);assert(fd != -1);printf("open FIFO success\n");while(1){printf("please input:\n");char buff[128] = {0};fgets(buff,128,stdin);write(fd,buff,strlen(buff)-1);if(strncmp(buff,"end",3)==0){break;}}close(fd);exit(0); }讀端代碼:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<assert.h> #include<fcntl.h> #include<sys/stat.h>int main() {int fd = open("fifo",O_RDONLY);assert(fd != -1);printf("FIFO open success\n");while(1){char buff[128] = {0};int n = read(fd,buff,127);if(n <= 0 || (strncmp(buff, "end", 3)==0)){break;}printf("%s\n",buff);}close(fd);exit(0); }(1)如果讀端或者寫端先打開,那么將會(huì)在open阻塞住 ,直至另一端也打開管道。
(2)寫端和讀端都打開后,讀端會(huì)在read處阻塞,寫端向管道中寫入數(shù)據(jù)后,讀端才正常執(zhí)行read,執(zhí)行完繼續(xù)在read阻塞。
(3)如果讀端關(guān)閉,寫端在向管道輸入數(shù)據(jù)后會(huì)觸發(fā)信號(hào)(SIGPIPE)自動(dòng)退出。
(4)如果寫端關(guān)閉,讀端read函數(shù)值會(huì)返回0。
當(dāng)寫端和讀端都在打開著,管道中的數(shù)據(jù)如果沒有及時(shí)讀出,不會(huì)消失。比如將讀端加上休眠10s,代碼如下:
寫端和讀端執(zhí)行情況:
發(fā)現(xiàn),在讀端還沒來得及讀走管道數(shù)據(jù)的時(shí)候?qū)懚嗽俅蜗蚬艿缹懭霐?shù)據(jù),管道中沒讀走的數(shù)據(jù)會(huì)被讀端下一次讀走。
3.無名管道
無名管道主要應(yīng)用于父子進(jìn)程間的通信。
無名管道的創(chuàng)建:
代碼演示:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<assert.h>int main() {int fd[2];int res = pipe(fd);assert(res != -1);pid_t pid = fork();assert(pid != -1);if(pid == 0){close(fd[1]);char buff[128] = {0};read(fd[0],buff,127);printf("child read:%s\n",buff);close(fd[0]);}else{close(fd[0]);char buff[128] = {0};printf("please input(less 128):\n");fgets(buff,128,stdin);write(fd[1],buff,strlen(buff)-1);close(fd[1]);}exit(0); }執(zhí)行結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的进程间通信(IPC机制)——管道的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux信号的使用
- 下一篇: 进程间通信——信号量及ipcs/ipcr