read() 不会阻塞在没有 O_NONBLOCK 标志的情况下打开的空 FIFO
Posted
技术标签:
【中文标题】read() 不会阻塞在没有 O_NONBLOCK 标志的情况下打开的空 FIFO【英文标题】:read() doesn't block on empty FIFOs opened without O_NONBLOCK flag 【发布时间】:2020-11-26 15:06:32 【问题描述】:pipe(7)
说:
如果一个进程试图从一个空管道中读取,那么 read(2) 将阻塞直到数据可用。如果一个进程试图写入一个完整的管道(见下文),那么 write(2) 会阻塞,直到从管道中读取了足够的数据以允许写入完成。通过使用 fcntl(2) F_SETFL 操作启用 O_NONBLOCK 打开文件状态标志,可以实现非阻塞 I/O。
下面我有两个用gcc在linux上编译的简单C程序:
reader.c
:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define STACKBUF_SIZE 128
#define FIFO_PATH "/home/bogdan/.imagedata"
signed int main(int argc, char **argv)
int fifo_fd = open(FIFO_PATH, O_RDONLY); // blocking... - notice no O_NONBLOCK flag
if (fifo_fd != -1)
fprintf(stdout, "open() call succeeded\n");
while (1)
char buf[STACKBUF_SIZE] = 0;
ssize_t bread = read(fifo_fd, buf, STACKBUF_SIZE);
fprintf(stdout, "%d - %s\n", bread, buf);
sleep(1);
close(fifo_fd);
return EXIT_SUCCESS;
writer.c
:
#define STACKBUF_SIZE 128
#define FIFO_PATH "/home/bogdan/.imagedata"
#define DATA "data"
int main(void)
int fifo_fd = open(FIFO_PATH, O_WRONLY); // blocks until reader opens on the reader end, however we always first open the reader so...
if(fifo_fd != -1)
ssize_t bwritten = write(fifo_fd, DATA, 5);
fprintf(stdout, "writer wrote %ld bytes\n", bwritten);
close(fifo_fd);
return EXIT_SUCCESS;
这些文件被编译成两个独立的二进制文件,gcc writer.c -Og -g -o ./writer
,对读者来说也是如此。
我首先从 shell 执行 reader 二进制文件,并且正如预期的那样,最初的 open()
调用阻塞,直到我也执行 writer。然后我执行编写器,其open()
调用立即成功,并将 5 个字节写入 FIFO(读取器正确显示),然后关闭 fd,让 FIFO 为空( ?)。
但是,阅读器的 while 循环中的以下 read()
调用根本不会阻塞,而只是返回 0。
除非我遗漏了某些东西(我可能是遗漏了),否则这与 pipe(7) 手册页概述的语义相冲突,因为 FIFO fd 在读取器和写入器中都没有O_NONBLOCK
标志是打开的。
【问题讨论】:
Joseph 指出这不是文档所说的,而且它没有意义:阻塞的目的是等待某些事情发生(这里,数据可用)。当管道的另一端关闭时,数据将永远无法使用,因此您的语义将使程序永远卡住,这不可能是处理这种情况的有用方法。 实际语义还可以方便地模仿从常规文件中读取时发生的情况,这有助于使管道透明并确保大多数程序可以自动处理管道输入。 【参考方案1】:您引用的手册部分仅适用于具有开放编写器的管道。两段下来,它是这样说的:
如果引用管道写入端的所有文件描述符都已关闭,则尝试从管道读取 (2) 将看到文件结尾(读取 (2) 将返回 0)。
【讨论】:
以上是关于read() 不会阻塞在没有 O_NONBLOCK 标志的情况下打开的空 FIFO的主要内容,如果未能解决你的问题,请参考以下文章