我的总体目标是将报告信息传递到命名管道,如果(并且仅当)有一个读取器连接到该命名管道。如果没有读者,我想避免构建报告信息等。由于这是在通过select()
处理其他数据流的情况下发生的,我想将命名管道添加到“准备好”的流中写作“。
所以,我想打开一个用于编写的命名管道,并且需要以某种方式将其提供给select()
,以便select()
只返回,以防在另一端有一个读者。命名管道。
通常情况下,如果没有阅读器,则open
通话已挂起;遗憾的是,我无法向open
提供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
作为准备写入返回,即使没有连接读者:
r, w, e = select.select([], [ fifo ], [])
print w[0]
这将始终同时打印fifo
值。
写入命名管道也不会挂起,无论我写多少:
fifo.write('foo')
我写的数据因没有连接阅读器而丢失。
打开我的虚拟阅读器时,我正在传递旗帜O_NONBLOCK
,因为否则这个开头也会挂起。我尝试了各种方法,但无法弄清楚如何正确地做到这一点。
有人能告诉我如何将写入命名管道与select()
结合起来吗?
(上面的代码是在Python中,但我想这个问题并没有真正连接到Python而是Linux / Unix问题,所以我不会将这个问题标记为Python。)
答案 0 :(得分:1)
请参阅man 7 fifo
WRT管道应如何非阻塞地工作。
进程可以在非阻塞模式下打开FIFO。在这种情况下,即使在写入端没有打开任何人,只读打开也会成功,只读打开将因ENXIO(没有这样的设备或地址)而失败,除非另一端已经打开。 / p>
在Linux下,打开FIFO进行读写将在阻塞和非阻塞模式下成功。 这可以用来打开FIFO进行写入,而没有可用的读取器。使用连接两端以便与自身通信的进程应该非常小心,以避免死锁。
这应该让你绕过dummy
黑客。然而,将fd与select()
一起使用,我认为是非首发。您可以改为使用select()
的短暂超时,以便在主循环内以write()
的间隔轮询fd,利用以下事实......
当进程尝试写入另一侧未打开读取的FIFO时,将向进程发送SIGPIPE信号。
...通过在调用之前将全局设置为true
并在SIGPIPE处理程序中设置false
以指示没有读者。
dummy
黑客(你真的要摆脱它)。
另一个也许更好的想法是为使用阻塞调用的fifo派一个处理程序,但也维护一个管道描述符到主进程的正常对(读/写)。其中一个(作者;即主要过程读取)可以与select()
一起使用。叉子等待open()
并在读卡器连接时发出主信号。
请注意,一旦您因为阅读器断开而达到EOF,您必须重新打开管道。不要继续使用相同的fd。
如果可行的话,我选择unix local socket超过fifo。