A FIFO special file (a named pipe) is similar to a pipe, except that it is accessed as part of the file system. It can be opened by multiple processes for reading or writing.
If O_NONBLOCK is clear:
An open() for reading only will block the calling thread until a thread opens the file for writing. An open() for writing only will block the calling thread until a thread opens the file for reading.
When opening a block special or character special file that supports non-blocking opens:
If O_NONBLOCK is set:
The open() function will return without blocking for the device to be ready or available. Subsequent behaviour of the device is device-specific.
If O_NONBLOCK is clear:
The open() function will block the calling thread until the device is ready or available before returning.
Otherwise, the behaviour of O_NONBLOCK is unspecified.
《read》
When attempting to read from an empty pipe or FIFO:
- If no process has the pipe open for writing, read() will return 0 to indicate end-of-file.
- If some process has the pipe open for writing and O_NONBLOCK is set, read() will return -1 and set errno to [EAGAIN].
- If some process has the pipe open for writing and O_NONBLOCK is clear, read() will block the calling thread until some data is written or the pipe is closed by all processes that had the pipe open for writing.
When attempting to read a file (other than a pipe or FIFO) that supports non-blocking reads and has no data currently available:
- If O_NONBLOCK is set, read() will return a -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() will block the calling thread until some data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data available.
现在简要说明一下遇到的问题:
要通过FIFO来进行进程间通信,用阻塞模式打开的话,进程会block在open函数上。估计谁也不希望在一个ipc类的initialize函数里面打开fifo文件时被block住。所以解法就是用非阻塞模式打开(|O_NONBLOCK),打开的问题我们解决了。
但这样我们还是没有办法像操作普通文件一样用阻塞方式读取数据,就算是用fcntl函数clear掉O_NONBLOCK标识也不行,这是因为上面的一段话“If no process has the pipe open for writing, read() will return 0 to indicate end-of-file. ”,也就是说在没有进程用写模式打开fifo文件的时候,去掉不去掉O_NONBLOCK标识read函数都会直接返回。恰巧我是想用echo向fifo中去写数据。echo不是一个常驻进程,所以在echo还没执行或者执行完以后,我们是没有办法去阻塞读fifo的。(一般的解决方法有:1.用循环,这个办法太土,不予讨论。2.还可以用select或者poll去异步监控fd事件,但感觉很不值当,虽然网上都说要用这种方法。3.用O_ASYNC去触发信号的方法没试过,感觉太繁琐。)
山穷水尽啦,疑无路啦,可这句诗还有后半句,叫"柳暗花明又一村"。
那就是在用只读非阻塞方式打开fifo文件的同时,然后再用只写阻塞方式再次打开该fifo文件。
再来看上面绿色的部分:
A process that uses both ends of the connection in order to communicate with itself should be very careful to avoid deadlocks.
既然man里面没说不许同一个进程同时打开fifo的两端,所以我们这么做一般也不会被人鄙视的。这样的具体原因也在上面的第二段绿色文字中:
When attempting to read from an empty pipe or FIFO:
If some process has the pipe open for writing and O_NONBLOCK is clear, read() will block the calling thread until some data is written or the pipe is closed by all processes that had the pipe open for writing.
也就是说我们自己保持一个该fifo文件的只写阻塞fd,我们也不会通过这个只写阻塞fd做任何输入操作,只是为了让那个只读fd能在读取数据时block在read函数中。
同时有下面这句作保障:
It can be opened by multiple processes for reading or writing.
从而保障了我们在用只写阻塞方式多打开了一次该fifo文件后,不会对外部的echo操作有任何影响。
特此感谢对open和read两个函数做了详细说明的OpenGroup !!!