日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

linux进程间通信:无名管道 pipe

發(fā)布時(shí)間:2023/11/27 生活经验 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux进程间通信:无名管道 pipe 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

      • 內(nèi)核層實(shí)現(xiàn)
        • 結(jié)構(gòu)
        • 通信原理
        • 特點(diǎn)
      • 使用
        • 函數(shù)聲明
        • 使用實(shí)例
          • 單向通信
          • 雙向通信
        • 編程注意事項(xiàng)
          • 管道中無數(shù)據(jù)時(shí)讀操作會(huì)阻塞
          • 將管道的寫端句柄關(guān)閉,不會(huì)影響讀端數(shù)據(jù)讀取
          • 管道中沒有數(shù)據(jù),寫操作關(guān)閉則讀操作會(huì)立即返回
          • 管道大小測試 64K
          • 管道發(fā)生寫滿阻塞,一旦有4k空間,寫繼續(xù)
      • 總結(jié)

內(nèi)核層實(shí)現(xiàn)

結(jié)構(gòu)

Linux操作系統(tǒng)中的無名管道結(jié)構(gòu)如下圖:

管道在內(nèi)核中的實(shí)現(xiàn)即如一個(gè)緩沖區(qū),內(nèi)核提供將該緩沖區(qū)以一個(gè)文件句柄的形式提供給用戶態(tài)供其調(diào)用,進(jìn)程1使用文件句柄f[0]讀,進(jìn)程2使用文件句柄f[1]寫。

無名管道的數(shù)據(jù)結(jié)構(gòu)聲明文件pipe_fs_i.h
執(zhí)行命令locate pipe_fs_i.h即可找到該文件路徑,查看管道文件描述符如下,由于我的內(nèi)核版本較新,可能該聲明和其他版本差異較大:

/***      struct pipe_inode_info - a linux kernel pipe*      @mutex: mutex protecting the whole thing*      @wait: reader/writer wait point in case of empty/full pipe*      @nrbufs: the number of non-empty pipe buffers in this pipe*      @buffers: total number of buffers (should be a power of 2)*      @curbuf: the current pipe buffer entry*      @tmp_page: cached released page*      @readers: number of current readers of this pipe*      @writers: number of current writers of this pipe*      @files: number of struct file referring this pipe (protected by ->i_lock)*      @waiting_writers: number of writers blocked waiting for room*      @r_counter: reader counter*      @w_counter: writer counter*      @fasync_readers: reader side fasync*      @fasync_writers: writer side fasync*      @bufs: the circular array of pipe buffers*      @user: the user who created this pipe**/struct pipe_inode_info {struct mutex mutex;wait_queue_head_t wait;unsigned int nrbufs, curbuf, buffers;unsigned int readers;unsigned int writers;unsigned int files;unsigned int waiting_writers;unsigned int r_counter;unsigned int w_counter;struct page *tmp_page;struct fasync_struct *fasync_readers;struct fasync_struct *fasync_writers;struct pipe_buffer *bufs;struct user_struct *user;
};

通信原理

  • 管道的內(nèi)核封裝 是一個(gè)文件(pipefs):
    a. 內(nèi)核將一個(gè)緩沖區(qū)與管道文件進(jìn)行關(guān)聯(lián)、封裝
    b. 用戶通過open/read/write/close等IO接口進(jìn)行讀寫

    讀寫過程如下所示,進(jìn)程運(yùn)行時(shí)使用管道會(huì)默認(rèn)打開一些文件句柄包括標(biāo)準(zhǔn)輸入流/輸出流/錯(cuò)誤 等。

特點(diǎn)

  • 像一個(gè)管道連接兩個(gè)進(jìn)程
  • 一個(gè)進(jìn)程作為輸入,一個(gè)進(jìn)程作為輸出
  • 用于親緣關(guān)系進(jìn)程之間的通信:共享資源

使用

函數(shù)聲明

  • int pipe(int pipefd[2]);
  • int pipe(int pipefd[2],int flags);

成功返回0,失敗返回-1

函數(shù)空間主要包含兩個(gè)文件描述符,一個(gè)用來讀,一個(gè)用來寫
詳細(xì)信息可以通過man 2 pipe查看系統(tǒng)調(diào)用信息

使用實(shí)例

單向通信

實(shí)現(xiàn)方式如下

代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>#define handle_error(msg)\
{perror(msg);exit(-1);}int main()
{int pipe_fd[2];if (pipe(pipe_fd) == -1) //創(chuàng)建管道handle_error("pipe");int f;f = fork();if (f == -1)handle_error("fork");if(f == 0){char str[100] = {0};printf("child process input :\n");scanf("%s",str);write(pipe_fd[1],str,strlen(str)); //子進(jìn)程向管道寫內(nèi)容close (pipe_fd[1]);_exit(0);}if (f > 0){char buf[100] = {0};read (pipe_fd[0],buf,30);printf("parent process output : %s\n",buf); //父進(jìn)程從管道讀內(nèi)容close(pipe_fd[0]);_exit(0);}return 0;
}

輸出如下:

zhang@ubuntu:~/test$ gcc test_pipe.c -o test_pipe
zhang@ubuntu:~/test$ ./test_pipe 
child process input :
aa
parent process output : aa
雙向通信

實(shí)現(xiàn)方式如下,父進(jìn)程和子進(jìn)程之間既可以讀也可以寫,該實(shí)現(xiàn)是通過兩個(gè)管道進(jìn)行讀寫處理。

代碼實(shí)現(xiàn)如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>#define handle_error(msg)\
{perror(msg);exit(-1);}int main()
{int pipe_fd[2];int pipe_fd2[2];if (pipe(pipe_fd) == -1 || pipe(pipe_fd2)) //創(chuàng)建兩個(gè)管道handle_error("pipe");int f;f = fork();if (f == -1)handle_error("fork");if(f == 0) //子進(jìn)程處理,子進(jìn)程先寫pipe_fd[1],再讀pipe_fd[0]{char str[100] = {0};char str2[100] = {0};printf("child process input :\n");scanf("%s",str);write(pipe_fd[1],str,strlen(str));close (pipe_fd[1]);read(pipe_fd2[0],str2,100);printf("in child process read : %s\n",str2);close(pipe_fd2[0]);_exit(0);}if (f > 0) //父進(jìn)程和子進(jìn)程相反,先讀pipe_fd[0],再寫pipe_fd2[1]{char buf[100] = {0};char buf2[100] = {0};read (pipe_fd[0],buf,30);printf("parent process output : %s\n",buf);close(pipe_fd[0]);printf("in parent process write: \n");scanf("%s",buf2);write(pipe_fd2[1],buf2,strlen(buf2));_exit(0);}return 0;
}

最終輸出如下:

zhang@ubuntu:~/test$ ./test_pipe_double 
child process input :
hello
parent process output : hello
in parent process write: 
world
zhang@ubuntu:~/test$ in child process read : world

編程注意事項(xiàng)

管道中無數(shù)據(jù)時(shí)讀操作會(huì)阻塞

如下代碼

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[50] = {0};//緩存if(pipe(fd)!=0)// 創(chuàng)建無名管道{perror("pipe fail: ");exit(1);}printf("%d %d\n",fd[0],fd[1]);//打開的文件描述符,此處為3,4 默認(rèn)打開 0,1,2,標(biāo)準(zhǔn)輸入,輸出,出錯(cuò)//管道中沒有數(shù)據(jù)的時(shí)候讀阻塞//  write(fd[1],"hello",10);  //此處不向管道寫數(shù)據(jù)時(shí),讀操作會(huì)阻塞,管道中有數(shù)據(jù)時(shí),讀操作后結(jié)束進(jìn)程read(fd[0],buf,10);printf("%s",buf);putchar(10); // '\n'return 0;
}

輸出如下

將管道的寫端句柄關(guān)閉,不會(huì)影響讀端數(shù)據(jù)讀取

代碼如下

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[50] = {0};//緩存if(pipe(fd)!=0)// 創(chuàng)建無名管道{perror("pipe fail: ");exit(1);}printf("%d %d\n",fd[0],fd[1]);//打開的文件描述符,此處為3,4 默認(rèn)打開 0,1,2,標(biāo)準(zhǔn)輸入,輸出,出錯(cuò)//管道中沒有數(shù)據(jù)的時(shí)候讀阻塞write(fd[1],"hello",10);  //此處不向管道寫數(shù)據(jù)時(shí),讀操作會(huì)阻塞,管道中有數(shù)據(jù)時(shí),讀操作后結(jié)束進(jìn)程close(fd[1]);read(fd[0],buf,10);close(fd[0]);printf("%s",buf);putchar(10); // '\n'return 0;
}

輸出正常如下:

zhang@ubuntu:~/test$ ./a.out 
3 4
hello
管道中沒有數(shù)據(jù),寫操作關(guān)閉則讀操作會(huì)立即返回

測試代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[50] = {0};//緩存if(pipe(fd)!=0)// 創(chuàng)建無名管道{perror("pipe fail: ");exit(1);}printf("%d %d\n",fd[0],fd[1]);//打開的文件描述符,默認(rèn)打開 0,1,2//寫端關(guān)閉,管道中無數(shù)據(jù),讀操作立即返回close(fd[1]);read(fd[0],buf,5);return 0;
}
zhang@ubuntu:~/test$ ./a.out 
3 4
管道大小測試 64K
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[65536] = {0};//緩存if(pipe(fd)!=0)// 創(chuàng)建無名管道{perror("pipe fail: ");exit(1);}int f = fork();int num = 0;if (f == 0) {int ret = write(fd[1],"123",1024);while (1 && ret != 0){ret = write(fd[1],"123",1024);printf("write size is %d\n",ret);num ++;printf("write count is %d\n",num);}close(fd[1]);_exit(1);}if (f > 0){printf("%d %d\n",fd[0],fd[1]);//打開的文件描述符,默認(rèn)打開 0,1,2//寫端關(guān)閉,管道中無數(shù)據(jù),讀操作立即返回read(fd[0],buf,65536);printf("write result is %s\n",buf);close(fd[0]);_exit(1);}return 0;
}

輸出如下,當(dāng)寫入數(shù)據(jù)達(dá)到64K時(shí)會(huì)阻塞

write count is 63
write size is 1024
write count is 64
...
管道發(fā)生寫滿阻塞,一旦有4k空間,寫繼續(xù)
include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[65536] = {0};//緩存if(pipe(fd)!=0)// 創(chuàng)建無名管道{perror("pipe fail: ");exit(1);}int f = fork();int num = 0;if (f == 0) {int ret = write(fd[1],"123",1024);while (1 && ret != 0){ret = write(fd[1],"123",4096);printf("write size is %d\n",ret);num ++;printf("write count is %d\n",num);}close(fd[1]);_exit(1);}if (f > 0){sleep(1);printf("get the wirte result is %d %d\n",fd[0],fd[1]);//打開的文件描述符,默認(rèn)打開 0,1,2//寫端關(guān)閉,管道中無數(shù)據(jù),讀操作立即返回read(fd[0],buf,4096);printf("write result is %s\n",buf);close(fd[0]);_exit(1);}return 0;
}

輸出如下

write count is 15
get the wirte result is 3 4 //讀出來一次,
write result is 123 
zhanghuigui@ubuntu:~/test$ write size is 4096  子進(jìn)程繼續(xù)寫入讀出的空間
write count is 16 //寫滿后又發(fā)生了阻塞
...  

總結(jié)

綜上可見,管道是應(yīng)用在擁有親緣關(guān)系的進(jìn)程之間的共享資源。
優(yōu)點(diǎn)也很明顯:
管道屬于系統(tǒng)調(diào)用,且數(shù)據(jù)存放在內(nèi)存之中,它的父子進(jìn)程通信過程效率非常高
缺點(diǎn)同樣也很明顯:
父子進(jìn)程通信交互并不友好,阻塞式的通信非常影響用戶體驗(yàn)

總結(jié)

以上是生活随笔為你收集整理的linux进程间通信:无名管道 pipe的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。