理论教育 Linux操作系统实践:匿名管道实现父子进程通信

Linux操作系统实践:匿名管道实现父子进程通信

时间:2023-11-25 理论教育 版权反馈
【摘要】:利用匿名管道实现父子进程间的通信, 子进程对父进程说“hello”。父、 子进程都产生后, 内存中的状态如图5.19 所示, 代码执行时子进程执行write 向管道写入, 父进程执行read 从管道读出, 从而完成一次单向的通信。图5.19父子进程利用匿名管道通信示意图父子进程并发执行, 此处的同步执行顺序是, 由于人为加入了sleep 控制, 导致子进程比父进程后执行, 但父进程中的read 需要等待子进程的write 执行后才能读数据, 所以最后执行的是父亲读出内容并输出。

Linux操作系统实践:匿名管道实现父子进程通信

匿名管道没有与缓冲区绑定的名字, 主要用于有亲缘关系的进程间通信, 通过调用pipe 函数创建管道, 函数原型如下:

函数调用成功返回0, 调用失败返回-1, 调用时会在内核开辟一块用于通信的缓冲区(称为管道), 管道有一个读端和一个写端, 通过参数传给两个文件描述符, fileds[0]指向管道的读端; fileds[1]指向管道的写端。 管道就如一个打开的文件, 通过抽象的文件操作调用read(fileds[0])或write(fileds[1])操作文件对应的内存区域, 读写数据其实就是读写缓冲区。

【例5-20】 利用匿名管道实现父子进程间的通信, 子进程对父进程说“hello”。

其执行结果如下。

父进程中通过pipe()调用申请创建第三方缓冲区并获得了该内存区域的读写端地址,该调用必须在fork 之前, 这样才能保证fork 通过克隆把读写端的地址复制一份给子进程。父、 子进程都产生后, 内存中的状态如图5.19 所示, 代码执行时子进程执行write 向管道写入, 父进程执行read 从管道读出, 从而完成一次单向的通信。

图5.19 父子进程利用匿名管道通信示意图

父子进程并发执行, 此处的同步执行顺序是, 由于人为加入了sleep 控制, 导致子进程比父进程后执行, 但父进程中的read 需要等待子进程的write 执行后才能读数据, 所以最后执行的是父亲读出内容并输出。(www.daowen.com)

【例5-21】 匿名管道通信并测试缓冲区大小实例。

查看Linux 内核代码, 能看到系统对默认缓冲区大小的设置为:

[root@localhost RPC]#grep "PIPE" /usr/src/kernels/3.10.0-957.el7.x86_64/include/linux/pipe_fs_i.h:

#define PIPE_DEF_BUFFERS 16(以页为单位的, 默认的页大小为4k)

可见, Linux 默认的pipe 缓冲区为64kB, 而2.6.35 之后的内核可使用函数fcntl 更改缓冲区大小。

下面示例代码利用pause 使子进程不读取数据, 同时为了防止代码的读写逻辑出错,在子进程一边关闭了管道的写端, 在父进程一边关闭了读端。 父进程执行的工作是一直向管道中写入数据: 父进程每次向管道中写入一个字符, 并将已经写入的字节数打印出来,当缓冲区写满而没有人读走时, 作为写入一方的父进程将阻塞, 于是可验证出pipe 缓冲区大小为64kB。

最后程序停止时输出: write pipe 65536, total size 65536B。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈