本文共 1908 字,大约阅读时间需要 6 分钟。
管道是最初的Unix 进程间通信(IPC)的方式,它的局限在于没有名字(有名管道FIFO下节讲),从而只能由有亲缘关系的进程间使用,例如父子进程。管道和FIFO都是使用read和write函数访问的。
管道由pipe函数创建,提供一个单向的数据流#includeint pipe(int pipefd[2]);
函数返回两个文件描述符,fd[0]和fd[1],0用于读,1用于写。
调用pipe函数会在内核中开辟一块缓存区用于通信,一个读端,一个写端,fd[0]指向读端,fd[1]指向写端。 父子进程如何通过管道实现通信? 1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端; 2、父进程调用fork创建子进程,子进程有两个文件描述符指向同一管道; 3、父进程关闭读端,子进程关闭写端。父进程可以往管道里写,子进程可以从管道里读,数据从写端流入,从读端流出,这样就实现了进程间通信。 fork完成之后://#include "stdio.h"#include "stdlib.h"#include "unistd.h"#include "errno.h"#include "string.h"int main(){ int _pipe[2]; int ret=pipe(_pipe); if(ret==-1)// { printf("creat pipe error!errno code is:%d\n",errno); return 1; } pid_t id = fork(); if(id<0) { printf("fork error!"); return 2; } else if(id==0)//child { close(_pipe[1]); char _mesg[100]; int j=0; while(j<6) { memset(_mesg,'\0',sizeof(_mesg)); int res = read(_pipe[0],_mesg,sizeof(_mesg)); printf("%d_%s strlenth is:%d\n",j,_mesg,res); j++; } } else{ //father close(_pipe[0]); int i=0; char* _mesg_c=NULL; while(i<6) { _mesg_c="i im coder"; write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); sleep(1); i++; } } return 0;}
运行结果:
管道通信的四中特殊情况:
1、所有指向管道写端的文件描述符都关闭了,仍有进程从管道的读端读取数据,当管道中剩余的数据都被读取之后,再次读取时会返回0,就像读到文件末尾一样; 2、指向管道写端的文件描述符没关闭,持有管道写端的进程也没有向管道中写数据,这是有进程从管道的读端读取数据,当管道剩余的数据都被读取后,再次读取进程会阻塞,直到管道中有数据可读了才读取数据并返回; 3、如果指向管道读端的文件描述符都关闭了,这是有进程向管道的写端写入数据,该进程会收到SIGPIPE,会导致进程异常终止; 4、如果指向管道读端的文件描述符没关闭,而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,在管道被写满时再次写入会阻塞,直到管道中有空位置了才写入数据并返回。管道通信的特点:
1、管道是半双工的,只能支持数据的单向流动;两进程间需要通信时需要建立起两个管道; 2、无名管道使用pipe()函数创建,只能用于父子进程或者兄弟进程之间; 3、管道对于通信的两端进程而言,实质上是一种独立的文件,只存在于内存中; 4、数据的读写操作:一个进程向管道中写数据,所写的数据添加在管道缓冲区的尾部;另一个进程在管道中缓冲区的头部读数据。参考:
1、 2、