我的总体目标是将报告信息传递到命名管道,如果(并且仅当)有一个读取器连接到该命名管道.如果没有读者,我想避免构建报告信息等.由于这是在通过select()处理其他数据流的情况下发生的,我想将命名管道添加到“已准备好写入”的流中”.
所以,我想打开一个用于编写的命名管道,并且需要以某种方式将它提供给select(),以便select()仅在命名管道的另一端有一个读取器时返回.
通常情况下,如果没有读卡器,则打开电话已挂起;不幸的是,我不能给select()打开一个动作 – 只有打开的文件描述符是有效的.
为了得到一个像样的文件描述符,我正在创建一个虚拟阅读器(我打开命名管道来自己阅读),然后打开它进行写入,然后再次关闭虚拟阅读器:
dummy = os.open(fifoPath, os.O_RDONLY | os.O_NONBLOCK)
# ^^^ without the NONBLOCK, this will hang until another process is ready to write
fifo = os.open(fifoPath os.O_WRONLY)
os.close(dummy)
如果我现在打开另一个读者,他将收到我写入命名管道的内容,因此这方面是有效的.
但是现在select()总是将fifo返回为ready-to-write,即使没有连接读取器:
r, w, e = select.select([], [ fifo ], [])
print w[0]
这将始终立即打印fifo值.
无论我写多少,写入命名管道也不会挂起:
fifo.write('foo')
由于没有连接读卡器,我写的数据就丢失了.
打开我的虚拟阅读器时,我正在传递标志O_NONBLOCK,否则这个开头也会挂起.我尝试了各种方法,但无法弄清楚如何正确地做到这一点.
任何人都可以告诉我如何将命名管道与select()结合使用?
(上面的代码是在Python中,但我想问题并不是真的与Python有关,而是与Linux / Unix有关,所以我不会将这个问题标记为Python.)
解决方法:
见man 7 fifo WRT管道应该如何工作非阻塞.
A process can open a FIFO in nonblocking mode. In this case, opening for read-only will succeed even if no-one 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 nonblocking mode. 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.
这应该让你绕过虚拟黑客.然而,使用带有select()的fd,我认为是非首发.您可以使用select()来使用短暂超时,以便于在主循环内以一定间隔使用write()轮询fd,利用以下事实……
When a process tries to write to a FIFO that is not opened for read on the other side, the process is sent a SIGPIPE signal.
…通过在调用之前将global设置为true而在SIGPIPE处理程序中将false设置为false以指示没有读取器.
但是,Python可能是一个问题,因为你应该已经获得了这个信号,但显然不是.这可能是因为虚假黑客(你真的必须摆脱它).
另一个也许更好的想法是为使用阻塞调用的fifo派一个处理程序,但也维护一个管道描述符到主进程的正常对(读/写).其中一个(作者;即主进程读取)可以与select()一起使用.当读取器连接时,fork等待open()并发出main信号.
请注意,一旦您因读卡器断开而达到EOF,您必须重新打开管道.不要继续使用相同的fd.
如果可行,我会选择unix local socket而不是fifo.