无名管道是单工的工作方式,即进程要么只能读管道,要么只能写管道。父子进程虽然都拥有管道的读端和写端,但是只能使用其中一个(例如,可以约定父进程读管道,而子进程写管道)。这样就应该把不使用的读端 或写端文件描述符关闭。
int fd[2]
亲缘
![](https://img-blog.csdnimg.cn/ffa4887cf9d44787895897341dc6b130.png)
创建无名管道的函数
#include <unistd.h>
int pipe(int pipefd[2]);
参数是个数组,这个函数的操作返回管道(
开口
)
两边的文件描述符(管道也是文件)。
可拿到管道两端的文件描述符。成功返回 0 ,失败返回-1。
例如:如果将父进程的读端
fd[0]
和子进程的写端
fd[1]
关闭。此时,父子进程之间就建立了一条“父进程。写入子进程读取”的通道。同样,也可以关闭父进程的 fd[1]
和子进程的
fd[0]
,这样就可以建立一条“父进程读取子进程写入”的通道。另外,父进程也可以创建 多个子进程,各个子进程都继承了管道的 fd[0]
和
fd[1] ,
这样就建立子进程之间的数据通道。
这里所说的管道主要指无名管道,它具有如下特点:
1、只能用于具有亲缘关系的进程之间的通信;
2、半双工的通信模式,具有固定的读端和写端;
3、管道可以看成是一种特殊的文件,对于它的读写可以使用文件
IO
如
read
、
write
函数;
4、管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符
fd[0]
和
fd[1]
。其中
fd[0] 固定用于读管道,而 fd[1]
固定用于写管道。 构成了一个半双工的通道。
![](https://img-blog.csdnimg.cn/8461b577501047b5af1b4d0b66fefaa3.png)
当管道中无数据时,读操作会阻塞。向管道中写入数据时,linux
将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么当缓冲区满的时候写操作将会一直阻塞。
只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的。SIFPIPE 信号
(
通常
Broken pipe
错误
)
。
特殊文件
,
例如
lseek
不能用来定位。
示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#define MAX 99999
//测试无名管道大小
int main(int argc, char const *argv[])
{
int fd[2], size = 1;
char buf[MAX];
pipe(fd);
while (1) {
//当写入字节大于管道大小发生阻塞
write(fd[1], "w", 1);
printf("pipe size : %d\n", size++);
}
return 0;
}
/*
pipe size : 65536
开始阻塞
*/