Linux--管道(pipe)
管道(pipe)
常用于父子进程,也用于有血缘关系的进程间的通信。
匿名管道所提供的进程间通信方式是单向的(只能是父读子写或父写子读,读写不能同时进行),且:
- 写端不关闭且不写,读端读完缓冲,此时阻塞;
- 读端关闭,写端还在操作,则写端进程异常而终止(收到SIGPIPE信号);
- 读端不关,写端写满缓冲区,此时写端阻塞,直到缓冲区为空。
使用pipe()函数进行父子进程间通信
基本步骤:
- 父进程创建管道,获取到指向管道的读、写两个文件描述符,fd[0]指向读端,fd[1]指向写端;
- fork出子进程,此时子进程也有两个读、写文件描述符指向相同的管道;
- 以父写子读为例,父进程关闭读端,子进程关闭写端,父进程写入数据,子进程读取数据。
父写子读代码实现:
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
int main(int argc,char **argv)
{int pipe_fd[2];pid_t pid;//创建管道if(pipe(pipe_fd) < 0){perror("pipe fail:");return -1;}printf("pipe ok\n");//创建子进程pid = fork();if(pid < 0){perror("fork fail:");return -1;}if(pid == 0){char c_buf[1024];printf("创建子进程\n");close(pipe_fd[1]);//关闭子进程读端int ret = read(pipe_fd[0],c_buf,sizeof(c_buf));if(ret < 0){perror("read fail\n");return -1;}printf("子进程读到:%s\n",c_buf);close(pipe_fd[0]);printf("子进程退出\n");return 0;}if(pid > 0){char p_buf[] = "hello child pross";close(pipe_fd[0]);//关闭父进程写端printf("父进程\n");write(pipe_fd[1],p_buf,sizeof(p_buf));printf("父进程写完成\n");close(pipe_fd[1]);printf("父进程退出\n");return 0;}
}
运行效果:
子进程中,并无sleep等函数,而父子进程各自运行,但是依然能确保子进程收到数据,因为read函数为阻塞函数,阻塞直到接收到数据,即遵循:管道内部处理了数据写完成然后才能读的机制
多对一的管道:
- 多个写进程关闭写管道后,读进程继续读管道会导致read返回0;
- 多个读进程关闭读管道后,写进程继续写管道并不会激发SIGPIPE信号,而是写成功返回。