理论教育 Linux操作系统实践:命名管道实现进程间通信,无阻塞特性

Linux操作系统实践:命名管道实现进程间通信,无阻塞特性

时间:2023-11-25 理论教育 版权反馈
【摘要】:命名管道就是通过提供通信双方一个有路径名的管道文件对应的缓冲区实现通信的。 打开另一个虚拟控制台②, 利用命令模拟写端:利用重定向符号把echo 命令结果写入管道, 而之前的控制台命令cat 会立即响应读出数据。图5.20利用命令操作命名管道2. 命名管道FIFO 的特点 允许无亲缘关系进程间的通信。参考5.3.3, 详见man 2 open。 命名管道不阻塞的通信。

Linux操作系统实践:命名管道实现进程间通信,无阻塞特性

如果两个进程没有亲缘关系, 各自独立的进程如何共知第三方缓冲区呢? 命名管道就是通过提供通信双方一个有路径名的管道文件对应的缓冲区实现通信的。 即使需要通信的多进程不存在亲缘关系, 但只要有权访问管道文件, 也就能彼此通过管道相互通信。

1. 命名管道在Shell 中的简单应用

(1) 新建命名管道。

命令行的操作实际上都是由底层代码实现的, 利用代码建管道方法如下。

(2) 打开一个虚拟控制台①, 利用命令模拟读端:

cat 读取普通数据文件就是把内容输出到屏幕上, 但对管道文件做操作就相当于读打开, 但是由于该文件没有数据写入, 所以cat 执行会阻塞, 如图5.20 所示。

(3) 打开另一个虚拟控制台②, 利用命令模拟写端:

利用重定向符号把echo 命令结果写入管道, 而之前的控制台命令cat 会立即响应读出数据。

(4) 如果先在控制台②执行echo, 由于没有对应的读端, echo 重定向输出到管道的操作也会阻塞等待另一个控制台上cat 的运行。

图5.20 利用命令操作命名管道

2. 命名管道FIFO 的特点

(1) 允许无亲缘关系进程间的通信。

(2) 不同于匿名管道只是临时对象, FIFO 以文件形式存在于文件系统中, 但不打开通信的话文件内并没有数据。

(3) 文件操作方式基于“先进先出”原理。

遵循先进先出(First In First Out)原则, 读总是从开始处返回数据, 写则把数据添加到末尾。 它们不支持诸如lseek()等文件定位操作。

(4) 提供灵活多样的同步机制。

命名管道函数原型如下。

①pathname: 创建的命名管道文件的路径和文件名, 也就是创建后FIFO 的名字。 若是一个已经存在的路径名时, 会返回EEXIST 错误。

②mode: 与打开普通文件的open()函数中的mode 参数相同。 参考5.3.3, 详见man 2 open。

函数调用成功则返回0, 若出错则返回值为-1, 相关出错信息含义如下。

(www.daowen.com)

3. 命名管道实例

【例5-22】 利用命名管道, 实现两个进程的通信。

其执行结果如下。

需要注意的是管道文件的建立位置和权限要注意合法, 比如如果是user 身份, 不小心把管道建在了root 的家目录下, 则程序运行时或许会由于权限问题报错。 本程序的运行需要在当前目录下新建一个管道文件fifotest 以便后面作为操作对象使用。

下面的测试执行过程是在两个命令控制窗口, 分别启动命令行操作管道文件fifotest,先执行读端操作, 然后启动写端操作, 最后的输出说明如下:

(1)先执行Rfifo 读方, 该进程执行到输出了标识①的语句就阻塞了, 因为管道默认规则要求读写两端同时存在才向下执行, 现在写端还没执行open, 所以读端将因为open 而阻塞等待;

(2)接着执行Wfifo, 先输出标识④的语句, 然后执行open, 由于读写两端都已存在着, 所以此处open 不阻塞并会唤醒之前由于open 阻塞的读端; 再然后可以看到②、 ⑤两语都立即输出了。

写端代码专门在write 前设置了sleep, 写端会睡眠后再执行write, 这就影响读端的read 要等待write, 所以表现为两个进程都会停住5 秒。 然后写端和读端的⑥、 ③两句依次输出。

本例重点要体验读写管道的两个进程在打开、 读写操作上的同步规则。 同步规则默认是阻塞模式的, 打开要双方都在, 没有数据或有写进程正在写入时, 进程会阻塞。

实际上同步运行时, 还有一些细节问题: 若写入的数据量不大于PIPE_BUF, 若管道内空间不足容纳, 进程睡眠等待空间够用时再一次性写完; 若写入的数据量大于PIPE_BUF, 内核将在管道缓冲区一有空闲区域就尝试写入数据, 写完数据才返回。

【例5-23】 命名管道不阻塞的通信。

为了编程更大的自由度和灵活性, 管道通信中的同步规则是有多种方式可选的。 Open函数调用时是否设置O_NONBLOCK 会影响进程操作管道的阻塞情况。

(1)打开规则: 若设置了O_NONBLOCK , 则只读打开立即返回; 写打开将返回出错,errno 值为ENXIO。

(2)读规则: 若设置了O_NONBLOCK , 则没数据时会返回-1, errno 为EAGAIN, 提醒以后再试。

(3)写规则: 若设置了O_NONBLOCK, 写入数据量大于PIPE_BUF 时, 写满所有管道空闲区后就返回, 数据不会全部写完。 若数据量小于PIPE_BUF, 进行原子性写入, 若缓冲区能够容纳请求写入的字节数就写完并成功返回, 否则返回EAGAIN 错误, 提醒以后再写。

若某个FIFO 的最后一个写进程关闭了该FIFO, 则将为该FIFO 的读进程产生一个文件结束标志。

下面的实例实现了读方不阻塞的持续读, 而写方完成10 次连续写入操作, 试体会读写间的同步。

其执行结果如下。

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

我要反馈