一、引言
(1)匿名管道可以实现本地的父子或兄弟进程间的通信。
(2)是半双工的,数据只能向一个方向流动,如果需要实现双方通信,使用两个管道。
二、pipe函数的使用
pipe函数的原型如下:
#include <unistd.h>
int pipe(int fd[2]);
管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示。
数组中的两个文件描述符以一种特殊的方式连接起来,数据基于先进先出的原则,写到fd[1]的所有数据都可以从fd[0]读回来。由于数据基于先进先出的原则,所以读取的数据和写入的数据是一致的。
下面的例子中,在父进程中创建管道,写入数据,在子进程中读入数据,通过匿名管道实现了进程间的通信
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
#define BUF_SIZE 1024
int main()
{
int data_process=0;
int fd[2];
pid_t pid;
if(pipe(fd)==0)
{
// 创建管道成功
// 创建子进程
pid = fork();
if(pid <0)
{
cout << "fork failed!" << endl;
exit(1);
}
else if(pid == 0)
{
close(fd[1]);
char buf[BUF_SIZE];
memset(buf,0,sizeof(buf));
while(1)
{
data_process = read(fd[0],buf,BUF_SIZE);
cout << "Read " << data_process << " bytes: "<< buf << endl;
if(strncmp(buf,"quit",4)==0)
break;
}
close(fd[0]);
return 0;
}
else
{
close(fd[0]);
char buf[BUF_SIZE];
memset(buf,0,sizeof(buf));
while(1)
{
cout << " > ";
cin.getline(buf,BUF_SIZE);
data_process = write(fd[1],buf,strlen(buf));
usleep(500);
if(strncmp(buf,"quit",4)==0)
break;
}
close(fd[1]);
return 0;
}
}
return 0;
}
注意:上述代码中,在父进程和子进程中分别关闭了fd[0]和fd[1],是因为使用fork会增加描述符的引用计数。
三、管道规则
(1)当管道中数据长度为0时,读端处于阻塞状态,等待写端写入数据
(2)当写端数据长度小于管道长度时,将以原子性写入数据
对读进程来说:
(3)当写端关闭时,当所有数据被读出后,read返回0
(4)当写端未关闭,当所有数据被读出后,读端阻塞
对写进程来说:
(5)当读端关闭时,如果写端数据长度大于管道长度时,写完管道长度时,则产生信号SIGPIPE后退出
(6)当读端为关闭,如果写端数据长度大于管道长度时,写完管道长度时,写端处于阻塞状态