Chinaunix首页 | 论坛 | 博客
  • 博客访问: 609373
  • 博文数量: 154
  • 博客积分: 2548
  • 博客等级: 少校
  • 技术积分: 1534
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-29 16:36
个人简介

爱咋咋地

文章分类

全部博文(154)

文章存档

2022年(15)

2021年(3)

2020年(1)

2018年(1)

2017年(1)

2014年(1)

2013年(4)

2012年(11)

2011年(19)

2010年(22)

2009年(71)

2008年(5)

分类: LINUX

2010-11-12 22:52:29

像操作普通文件一样操作FIFO --- 非阻塞方式打开,阻塞方式读取
今天用fifo在进程间传输数据时发现:fifo在阻塞和非阻塞方式的操作都和普通文件存在很大的不同,多方参考和查阅资料以后发现fifo有如下特点:
(注:下面加颜色的语句都是较为关键的部分,蓝色的是问题,红色是解法,绿色是关键)
 
man 3 mkfifo:
创建fifo的函数,再次不再累诉
 
man 4 fifo:
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.
 
The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.
 
A process can open a FIFO in non-blocking mode. In this case, opening for read only will succeed even if noone has opened on the write side yet; opening for write only will fail with ENXIO (no such device or address) unless the other end has already been opened.
 
Under Linux, opening a FIFO for read and write will succeed both in blocking and non-blocking mode. POSIX leaves this behaviour undefined. This can be used to open a FIFO for writing while there are no readers available. A process that uses both ends of the connection in order to communicate with itself should be very careful to avoid deadlocks.
 
man 2 open
man 2 read
这两个文档对fifo的操作介绍较少
 
在open group中
这两个页面对fifo的操作介绍的较为详细:
《open》
O_NONBLOCK
When opening a FIFO with O_RDONLY or O_WRONLY set:
If O_NONBLOCK is set:
An open() for reading only will return without delay. An open() for writing only will return an error if no process currently has the file open for reading.

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 !!!

阅读(9087) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~