进程间通信常见方式-管道
学习目标:
掌握进程间通信方式。
掌握管道基本用法。
进程间通信常见方式:
Linux环境下,进程地址空间相互独立,每个进程都有各自的用户地址空间,任何一个进程的全局变量在另一个进程都看不到,所有进程与进程之间不能相互访问,要交换数据必须通过进程,在内核开辟一块缓冲区,将进程数据从用户空间拷贝到内核缓冲区,另一个进程再从内核缓冲区把数据读走,内核提供的该机制称为进程间通信(IPC)。
现今常用的进程间通信方式如下:
- 管道
- 信号(开销最小)
- 共享映射区
- 本地套接字(最稳定)
管道:
管道:管道是最基本的IPC机制,无名管道只能用于亲缘关系的进程间完成数据传递。调用pipe函数即可创建一个管道,有如下特质:
- 其本质是一个伪文件(实为内核缓冲区)。
- 由两个文件描述符引用:一个表示读端,一个表示写端。
- 规定数据从管道的写端流入管道,从读端流出。
管道的原理:管道实为内核使用环形队列机制,借助内核缓冲区(4K大小)实现。
管道局限性:
- 数据不能进程自己写,自己读。
- 管道中的数据不能反复读取,一旦读取,管道中不再存在。
- 用半双工通信方式,数据只能单方向流动。
- 亲缘关系进程间可用。
pipe函数:
pipe函数:用于创建一个管道实现进程间通信(头文件 unistd.h) 。函数调用返回R/W两个文件描述符,无需open,需要手动close,其中fd[0]
为读,fd[1]
为写。
- 父进程调用pipe函数创建管道,得到指向读写两端的两个文件描述符
fd[0]
,fd[1]
。 - 父进程调用fork创建子进程,子进程也有两个文件描述符指向同一管道。
- 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道写入数据,子进程将管道中的数据读出。使用环形队列方式实现,所有数据从写端流入,从读端流出,来实现进程间通信。
函数原型如下:
int pipe(int pipefd[2]);
参数
pipefd[0]:读端
pipefd[1]:写端
返回值
成功:0
失败: -1 设置errno
管道读写行为:
**读管道**:- 管道有数据:read返回实际读到的字节数。
- 管道无数据:
1. 无写端:read返回0(类似读到文件尾)。
2. 有写端:read阻塞等待。
写管道: - 无读端:异常终止。(SIGPIPE导致的)
- 有读端:
1. 管道已满:阻塞等待。
2. 管道未满:返回写出的字节个数。
fifo管道:
fifo管道:用于无亲缘关系的进程间通信。
int mkfifo(const char *pathname,mode_t mode);
参数
pathname:文件路径名。
mode:
- O_RDONLY:只读方式。
- O_WRONLY:只写方式。
- O_NONBLOCK:非阻塞方式。
返回值
成功:0
失败:-1 设置errno。
补充:
文件实现进程间通信:打开的文件是内核中的一块缓冲区。多个无亲缘关系的进程,可以同时访问该文件。