linux进程通信———有名管道FIFO
引言:无名管道的一个重大限制是它没有名字,通信范围限定在具有血缘关系的进程间。有名管道以FIFO文件形式存在于文件系统中。这样即使与FIFO创建进程不存在血缘关系的进程,只要访问该路径,就能够通过FIFO通信。本篇笔记包括FIFO介绍、代码实例、内核实现。
一、FIFO简介
1.1、“有名”管道:
FIFO指代先进先出(first in, first out),Unix中的FIFO类似于管道。它是一个单向(半双工的数据流)。不同于管道的是,每个FIFO有一个路径名与之对之关联,从而允许无亲缘关系的进程访问同一个FIFO,进行通信。FIFO也称为有名管道(named pipe)。
1.2、创建:
FIFO由mkfifo()函数创建,函数原型为:
int mkfifo(const char *pathname, mode_t mode)
- const char *pathname:是一个普通的unix路径名,它是该FIFO的名字。
- **mode:**mode参数指定FIFO权限位,它是S_IRUSER(属主读)、S_IWUSR(属主写)、S_IRGRP(组成员读)、S_IWGRP(组成员写)、S_IROTH(其他用户读)、S_IWOTH(其他用户写)这六个常值按位或组成的。
mkfifo函数已隐含制定O_CREAT | O_EXCL,也就是说,它要么创建一个新的FIFO,要么返回一个EEXIST错误(所指定名字的FIFO已经存在)。如果不希望创建一个新的FIFO,那么就改为调用open而不是mkfifo。要打开一个已经存在或希望创建一个新的FIFO,应先调用mkfifo,再检查它是否返回EEXIST错误,若返回该错误则改为调用open。
1.3、FIFO的打开规则:
1)、如果当前打开操作是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置了阻塞标志);或者,成功返回(当前打开操作没有设置阻塞标志)。
2)、如果当前打开操作是为写而打开FIFO时,如果已经有相应进程为读而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作设置了阻塞标志);或者,返回ENXIO错误(当前打开操作没有设置阻塞标志)。
总之,一旦设置了阻塞标志,调用mkfifo建立好之后,那么管道的两端读写必须分别打开,有任何一方未打开,则在调用open的时候就阻塞。对管道或者FIFO的write总是向末尾添加数据,对它们的read总是从开头返回数据,对管道或者FIFO调用lseek,返回ESPIPE错误。
1.4、FIFO中读取数据:
如果一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。并且有进程写打开FIFO,且当前FIFO内没有数据,即此时管道的两端都建立好了,但是写端还没有写数据。
1)、则对于设置了阻塞标志的读操作来说,将一直阻塞(就是block住了,等待数据。它并不消耗CPU资源,这种进程的同步方式对CPU而言是非常有效率的。)
2)、对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。
对于设置了阻塞标志的读操作来说,造成阻塞的原因有两种:
1)、FIFO内有数据,但有其它进程在读这些数据(对于各个读进程而言,这根有名管道是临界资源,大家得互相谦让,不能一起用。)
2)、FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。
需要注意的一点是:读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多