O_NONBLOCK是否设置了文件描述符或基础文件的属性?
从我在Open Group网站上read
fcntl
, open
, read
和write
,我得到的印象是O_NONBLOCK
是否设置在文件描述符上,因此非阻塞I / O是否与描述符一起使用,应该是该文件描述符的属性而不是底层文件。 例如,作为文件描述符的属性意味着,如果我复制文件描述符或打开另一个描述符到同一文件,那么我可以使用阻塞I / O和一个非阻塞I / O与另一个。
然而,尝试使用FIFO,似乎不可能同时为FIFO提供阻塞I / O描述符和非阻塞I / O描述符(因此,是否设置O_NONBLOCK
是基础文件的属性[FIFO] ]):
#include #include #include #include #include int main(int argc, char **argv) { int fds[2]; if (pipe(fds) == -1) { fprintf(stderr, "`pipe` failed.\n"); return EXIT_FAILURE; } int fd0_dup = dup(fds[0]); if (fd0_dup <= STDERR_FILENO) { fprintf(stderr, "Failed to duplicate the read end\n"); return EXIT_FAILURE; } if (fds[0] == fd0_dup) { fprintf(stderr, "`fds[0]` should not equal `fd0_dup`.\n"); return EXIT_FAILURE; } if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { fprintf(stderr, "`fds[0]` should not have `O_NONBLOCK` set.\n"); return EXIT_FAILURE; } if (fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK) == -1) { fprintf(stderr, "Failed to set `O_NONBLOCK` on `fd0_dup`\n"); return EXIT_FAILURE; } if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { fprintf(stderr, "`fds[0]` should still have `O_NONBLOCK` unset.\n"); return EXIT_FAILURE; // RETURNS HERE } char buf[1]; if (read(fd0_dup, buf, 1) != -1) { fprintf(stderr, "Expected `read` on `fd0_dup` to fail immediately\n"); return EXIT_FAILURE; } else if (errno != EAGAIN) { fprintf(stderr, "Expected `errno` to be `EAGAIN`\n"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
这让我想到:是否有可能拥有一个非阻塞I / O描述符并阻止I / O描述符到同一个文件,如果是这样,它是否依赖于文件类型(常规文件,FIFO,块特殊文件) ,字符特殊文件,套接字等)?
O_NONBLOCK是打开文件描述的属性,不是文件描述符的属性,也不是底层文件的属性。
是的,你可以为同一个文件打开单独的文件描述符,其中一个是阻塞的,另一个是非阻塞的。
您需要区分FIFO(使用mkfifo()
创建)和管道(使用pipe()
创建)。
请注意,阻止状态是“打开文件描述”的属性,但在最简单的情况下,文件描述符和打开文件描述之间存在一对一的映射。 open()
函数调用创建一个新的打开文件描述和一个引用打开文件描述的新文件描述符。
使用dup()
,您有两个文件描述符共享一个打开的文件描述,属性属于打开的文件描述。 fcntl()
的描述表明F_SETFL会影响与文件描述符关联的打开文件描述。 请注意, lseek()
调整与文件描述符关联的打开文件描述的文件位置 – 因此它会影响从原始文件描述符复制的其他文件描述符。
从代码中删除error handling以减少它,您有:
int fds[2]; pipe(fds); int fd0_dup = dup(fds[0]); fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK);
现在fd0_dup和fds [0]都引用相同的打开文件描述(因为dup()
),因此fcntl()
操作影响了两个文件描述符。
if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... }
因此,这里观察到的行为是POSIX所要求的。