在Linux系统中,有时候需要多个进程相互协作,共同完成某项任务。进程之间需要传递消息,有时候需要同步来协调彼此的工作。因此进程间通信应运而生,进程间通信方式有管道、共享内存、消息队列、信号量等,今天我会详细讲述匿名管道
管道
- 本质:
内核中的一块缓冲区 - 原理:
多个进程通过访问同一块缓冲区实现数据传输 - 分类:
匿名管道(只能用于具有亲缘关系的进程间通信)
命名管道(同一主机任意进程间通信) - 特性:
半双工通信:可选择方向的单向通信。
提供字节流传输服务:有序的(数据先进先出),可靠的(保证数据可以被对方拿到),基于连接的流式传输(有读有写,所有读端关闭,则write异常,所有写端关闭,则read返回0)
自带同步与互斥:
互斥:通过同一时间进程对临界资源的唯一访问实现访问操作安全。
同步:通过一些条件判断让进程对临界资源的访问更加合理有序。
互斥的体现:对管道进行写入操作大小不超过PIPE_BUF大小,则保证操作的原子性。(原子性:不可分割的特性)
同步的体现:若管道没有数据,则read阻塞,管道数据满了,则write阻塞
管道的生命周期随进程–不人为干预,所有打开管道的进程退出后,管道缓冲区就会被释放
管道的使用(匿名管道)
- 创建管道
- 向管道写入数据
- 从管道中读取数据
1、在Linux下,可以使用如下接口创建管道:
#include<unistd.h>
int pipe(int pipefd[2]);
如果创建成功,返回值为0,如果失败,返回值为-1;
2、成功调用后,可以对写入端描述符pipefd[1]调用write:
write(pipefd[1],wbuf,count);
一旦向管道的写入端写入数据后,就可以对读取端操作符pipefd[0]调用read,读出管道的内容
3、在读取端调用read:
read(pipefd[0],rbuf,count);
整个流程全部完成之后用一幅图来表示:
但前面提到的匿名管道是用于具有亲缘关系的进程之间通信,所以应该在一个进程调用子进程之前进行管道的创建然后进行fork();
fork之后的进程如图所示:(当然也可以父进程读,子进程写)
注意:
- 只有当所有的写入端描述符都已关闭,且管道中的数据都被读出,对读取端描述符调用read函数才会返回0(即读到EOF标志)
- 如果所有读取端描述符都已关闭,此时进程再次往管道写入数据,写操作会失败。
- 当所有的读取端和写入端都关闭后,管道才能被销毁