我有两个进程A和B.通信流程始终是A - > B,但我需要使用命名管道,因为我必须在B进程内的select调用中使用管道文件描述符,并且当任何或两个进程退出时,写入管道的数据必须保持不变。
管道两端以非阻塞模式打开。在流程A:
int push_fifo_fd = open(FIFO_NAME, O_WRONLY | O_NONBLOCK | O_CREAT, 0644);
在流程B中:
int fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK | O_CREAT, 0644);
Q1。 进程B使用curl多接口,因此我得到curl多句柄的fd_sets并将“fd”描述符添加到读取fd_set,而不是调用select,以获得可用于读取和写入的文件描述符。在每次调用调用中,“fd”包含在结果读取fd_set中,但是读取返回0,即使写入结束也是如此。这导致进程B使用100%的处理器时间。我提到我不知道订购哪个管子的末端是打开的。来自B的相关代码:
while (1)
{
fd_set read_fds, write_fds, err_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&err_fds);
FD_SET(fifo_fd, &read_fds);
// some code
ccode = curl_multi_fdset(curlm, &read_fds, &write_fds, &err_fds, &max_fd);
max_fd = MAX(max_fd, fifo_fd);
rc = select(max_fd + 1, &read_fds, &write_fds, &err_fds, &timeout);
switch (rc)
{
case -1:
WARN("select");
continue;
case 0:
default:
{
if (FD_ISSET(fifo_fd, &read_fds))
{
// read from the fifo_fd
}
/* Now look at the handles that need attention */
int old_running_handles = running_handles;
ccode = curl_multi_perform(curlm, &running_handles);
if (ccode != CURLM_OK && ccode != CURLM_CALL_MULTI_PERFORM)
{
WARN("curl_multi_perform error: %s", curl_multi_strerror(ccode));
continue;
}
if (running_handles != old_running_handles)
{
CURLMsg *curl_msg;
int left_msgs = 0;
while ((curl_msg = curl_multi_info_read(curlm, &left_msgs)) != NULL)
{
// treat each easy handle
}
}
}
break;
}
}
Q2。在“man 7 fifo”中说“进程可以在非阻塞模式下打开FIFO。在这种情况下,即使在写入端没有人打开,只读打开也会成功,只写打开会失败使用ENXIO(没有这样的设备或地址),除非另一端已经打开。“但是进程A总是可以在非阻塞模式下成功打开管道的写入端,即使读取端未打开也是如此。这是为什么?我测试的平台是Ubuntu服务器12.04.3,内核3.8.0-29。
答案 0 :(得分:0)
由于:
在Linux下,打开FIFO进行读写将在阻塞和非阻塞模式下成功。 POSIX未定义此行为。这可用于打开FIFO进行写入,而没有可用的读取器。使用连接的两端以便与自身通信的进程应该非常小心以避免死锁。
答案 1 :(得分:0)
预计select()
或poll()
会出现Q1。请参见linked question。一个合适的解决方案是在同一fifo上打开另一个fd,然后关闭原来的fd。
我相信Q2也有望在某些版本的内核上使用。 man 7 fifo有一个关于它的段落:
Under Linux, opening a FIFO for read and write will succeed both in
blocking and nonblocking mode. POSIX leaves this behavior undefined.
This can be used to open a FIFO for writing while there are no
readers available.
该段似乎声称您可以随时成功打开fifo的写入端,正如原始作者在第二季度所观察到的那样。
尽管似乎与上一段矛盾,因为man 7 fifo页上还引用了原始问题,该问题基本上是说公开将失败而不是成功:
A process can open a FIFO in nonblocking mode. In this case, opening
for read-only succeeds even if no one has opened on the write side
yet and opening for write-only fails with ENXIO (no such device or
address) unless the other end has already been opened.
我看到在4.9.37内核上,当读端未打开时,以非阻塞模式打开写端将失败。我猜它一定已经从3.8版本更改为4.9版本。