O_NONBLOCK是设置文件描述符还是基础文件的属性?
-
04-10-2019 - |
题
根据我在公开小组网站上阅读的内容 fcntl
, open
, read
, , 和 write
, ,我得到的印象是是否 O_NONBLOCK
是在文件描述符上设置的,因此是否与描述符一起使用非阻滞I/O,应该是该文件描述符而不是基础文件的属性。作为文件描述符的属性,例如,例如,如果我复制文件描述符或将另一个描述符打开到同一文件,那么我可以将阻止I/O与另一个和非块I/O与另一个使用。
但是,尝试使用FIFO,看来不可能同时具有封闭的I/O描述符和非阻滞I/O描述符(因此是否是 O_NONBLOCK
设置是基础文件[FIFO]的属性):
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
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,block special文件,角色特殊文件,插座等)?
解决方案
O_NONBLOCK是打开文件描述的属性,而不是文件描述符,也不是基础文件的属性。
是的,您可以为同一文件打开单独的文件描述符,其中一个是阻止的,另一个是非封锁的。
您需要区分FIFO(使用 mkfifo()
)和管道(使用 pipe()
).
请注意,阻止状态是“打开文件描述”的属性,但是在最简单的情况下,文件描述符和打开文件描述之间有一对一的映射。这 open()
函数调用创建一个新的打开文件描述和一个新的文件描述符,该描述符指的是打开文件描述。
当您使用时 dup()
, ,您有两个文件描述符,共享一个打开的文件描述,并且该属性属于打开文件描述。描述 fcntl()
说F_SETFL会影响与文件描述符关联的打开文件描述。注意 lseek()
调整与文件描述符关联的打开文件描述的文件位置 - 因此它会影响从原始文件重复的其他文件描述符。
从您的代码中删除错误处理以减少它,您有:
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需要此处观察到的行为。