上篇文章的简述,我相信大家对管道的概念有了模糊的认识,本文通过代码实例来强化对管道的理解.
创建管道主要用到pipe函数,pipe的原型如下:
一、函数原型
#include <unistd.h>
int pipe(int pipefd[2]);
参数:一个整型数组,管道创建成功后,pipefd[0]表示管道的读端,pipefd[1]表示管道的写端.
成功返回0,失败返回-1,同时errno被设置.
二、父子进程通信
上文中,我们描述了父子进程通过管道来进行通信的整个过程,现在我们用C语言来实现:
#include<stdio.h> #include<unistd.h> int main(){ int fds[2] = {0}; //1.创建管道 if(pipe(fds)==-1){ perror("pipe"); return 1; } //2.fork子进程 pid_t pid = fork(); if(pid > 0){ //father //3.父进程关闭读端,向写端写入数据 close(fds[0]); char buff[1024]={0}; printf("parent to child#"); fflush(stdout); ssize_t s = read(0,buff,sizeof(buff)-1); buff[s-1] = 0; write(fds[1],buff,s); close(fds[1]); }else if(pid==0){ //child //3.子进程关闭写端,从读端读出数据 close(fds[1]); char buff[1024]={0}; ssize_t s = read(fds[0],buff,sizeof(buff)); printf("child to receive#%s\n",buff); close(fds[0]); }else{ perror("fork"); return 2; } wait(NULL); //回收子进程 return 0; }
上述代码中,我们展示的是父子进程普通的通信情况,除了正常情况之外,我们还需考虑四种异常情况:
三、四种情况
为了节省文章篇幅,代码部分省略,读者可以自行测试.
1.父进程不断向管道中写数据,子进程不从管道中读取数据,子进程fds[0]读端保持开启.
这种情况将导致管道被写满,同时父进程被阻塞,直到管道中有空位置.
2.父进程不断向管道中写数据,子进程不从管道中读取数据,子进程关闭了fds[0]读端.
这种情况下,父进程会收到SIGPIPE信号,进而被终止.
3.父进程向管道中写了一些数据,子进程不断从管道中读取数据,父进程fds[1]写端保持开启.
这种情况下,子进程将管道中数据读取完毕之后,会进入阻塞状态.直到管道中有新数据产生.
4.父进程向管道中写了一些数据,子进程不断从管道中读取数据,父进程关闭了fds[1]写端.
这种情况下,子进程会读完管道中数据,最后read返回0,就像读到文件末尾一样.
时间: 2024-10-25 15:29:24