[英]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()
它也将立即返回与POLLHUP
在revents
。
如OP所述,正确的解决方法是重新打开FIFO。
由于Linux内核仅维护一个内部管道对象来表示每个打开的FIFO(请参阅man 7 fifo和man 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.