管道在两端都以非阻塞模式打开。在进程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的multi接口,因此我获取curl multi句柄的fd_sets,将“fd”描述符添加到read fd_set中,然后调用select函数获取可读和可写的文件描述符。每次调用select时,“fd”都包含在结果read fd_set中,但即使写端打开了,read函数也会返回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。
FIFO_NAME
文件确实是一个 FIFO,那么在打开它进行读写时使用O_CREAT
是不可取的。如果open()
必须创建它,则会将其创建为普通文件,这样做是适得其反的。 - John Bollingermkfifo FIFO; (echo "Hello World" > FIFO) & (echo "Hi" < FIFO); (echo "Goodbye, Cruel World!" > FIFO) & cat FIFO; rm -f FIFO
— 输出是Hi
和Goodbye, Cruel World!
(加上作业控制信息)。信息Hello World!
丢失了。将echo "Hi" < FIFO
更改为cat FIFO
,则可以看到Hello World!
(而没有 "Hi",因为它没有被写入任何地方)。 - Jonathan Leffler