繁体   English   中英

Linux命名为fifo non-blocking read select返回假read_fds

[英]Linux named fifo non-blocking read select returns bogus read_fds

类似于不久前在内核3.x上问问题 ,但我在4.9.37上看到了。 使用mkfifo -m 0666创建命名的fifo。 在读取方面,它用

int fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK);

结果fd传递给对select()的调用。 一切正常,直到我运行echo >> <fifo-name>

现在,在select()返回之后, fd出现在read_fds fd上的read()将返回一个字节的数据。 到现在为止还挺好。

下次调用select()并返回时, fd仍出现在read_fds ,但read()将始终返回零,意味着没有数据。 实际上,读取端将消耗100%的处理器容量。 这与所引用问题所观察到的问题完全相同。

有人看到过同样的问题吗? 以及如何解决或正确解决呢?

我已经弄清楚了,如果我关闭了fifo的读取端,然后再次将其重新打开,它将可以正常工作。 可能没问题,因为我们没有发送大量数据。 虽然这不是一个不错的方法或一般的解决方法。

这是预期的行为,因为输入结束的情况导致read()不会阻塞; 它立即返回0。

如果您看一下man 2 select ,它将清楚地表明,如果该描述符上的read()不会阻塞(在select()调用时),则会在readfds中设置一个描述符。

如果您使用poll()它也将立即返回与POLLHUPrevents


如OP所述,正确的解决方法是重新打开FIFO。

由于Linux内核仅维护一个内部管道对象来表示每个打开的FIFO(请参阅man 7 fifoman 7管道 ),因此Linux中的健壮方法是在遇到输入结束时向FIFO打开另一个描述符( read()返回0),然后关闭原始文件。 两个描述符都打开的时间内,它们引用相同的内核管道对象,因此不会出现争用窗口或数据丢失的风险。

在伪C中:

fifoflags = O_RDONLY | O_NONBLOCK;
fifofd = open(fifoname, fifoflags);
if (fifofd == -1) {
    /* Error checking */
}

/* ... */

/* select() readfds contains fifofd, or
   poll() returns POLLIN for fifofd: */

    n = read(fifofd, buffer, sizeof buffer)
    if (!n) {
        int tempfd;

        tempfd = open(fifopath, fifoflags);
        if (tempfd == -1) {
            const int cause = errno;
            close(fifofd);

            /* Error handling */

        }
        close(fifofd);
        fifofd = tempfd;

        /* A writer has closed the FIFO. */

    } else
        /* Handling for the other read() result cases */

Linux中的文件描述符分配策略是tempfd将是编号最小的空闲描述符。

在我的系统(Core i5-7200U笔记本电脑)上,以这种方式重新打开FIFO不到1.5 µs。 也就是说,每秒可以完成约680,000次。 我认为,即使在低功率的嵌入式Linux计算机上,这种重新开放也不是任何明智情况的瓶颈。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM