如何在命名管道(mkfifo)上执行非阻塞的fopen操作?

23
如果我有一个程序使用mkfifo创建并尝试打开命名管道,如何在不阻塞的情况下打开管道进行读取或写入操作?
具体来说,我正在编写一个C程序,可以带或不带Java编写的GUI界面。
在C程序中,我成功地使用mkfifo创建了命名管道,但当我执行操作时,会发生阻塞。
FILE* in = fopen(PIPE_IN, "r"); /* Where PIPE_IN is the filename*/

fopen不会返回,直到GUI打开写入管道。 我想做的是让那个管道准备好被读取,一旦(如果)GUI决定写入它 - 我将在select()调用中放置文件描述符。 可以合理地期望java GUI可能根本不会启动,因此我不能指望它在任何特定时间甚至根本没有打开管道的另一端。

我还将打开第二个管道进行写入,并且我认为我将面临相同的问题。 此外,我无法在没有读取器的输出管道上设置O_NONBLOCK。

有什么建议吗?

(这在Linux系统上运行)


在 select() 在输入管道上触发之前,您需要打开输出管道吗? - Tim Post
@tinkertim - 从技术上讲,我想不是这样的 - 我已经在设置函数中将它们都设置好了,但我可以先设置输出管道,然后调用select,为什么? - Zxaos
1个回答

23
您可以使用open()函数打开管道,选项设置为O_RDONLY | O_NONBLOCK,如果您需要C流,可以使用fdopen()函数获取。但是,select()的使用可能会有问题-据我所知,对于读取未被写入的管道文件描述符,它始终准备好读取,并且read()返回0,因此select()会一直触发。

一个解决方案是使用O_RDWR选项打开管道,在其中至少有一个写入器程序(例如C++程序),这样可以解决问题。


1
我会为读者尝试一下 - 但是我无法在输出管道上设置O_NONBLOCK... - Zxaos
1
POSIX标准指出(关于select()函数):“当使用O_NONBLOCK参数调用输入函数不会阻塞时,描述符应被视为准备好读取,无论该函数是否能成功传输数据。”(POSIX.1:2008)。 - Jonathan Leffler
2
打开 O_RDWR 管道会导致死锁,除非实际上还有另一个进程也打开了该管道,程序才能读取(或写入)。 - Jonathan Leffler
1
@Jonathan Leffler - 但我可以以RDWR方式打开它,并通过轮询来查看另一个进程何时实际写入它吗?这不会导致死锁,对吗? - Zxaos
1
是的,这应该在select()中阻止。对于管道的写入端没有这样的解决方案,可能最好的办法是在从Java程序接收到一些提示后打开写入端口。 - jpalecek
@jpalecek,是的,昨晚我意识到这就是我必须做的事情,思考为什么tinkertim在原始问题的评论中询问顺序后。 - Zxaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接