Dan*_*ien 19 c file-descriptor nonblocking fcntl posix-api
从我一直在阅读上由The Open Group网站上fcntl,open,read,和write,我得到的印象是,是否O_NONBLOCK被设置在一个文件描述符,因此非阻塞I/O是否使用与描述符,应该是一个属性该文件描述符而不是底层文件.作为文件描述符的属性意味着,例如,如果我复制文件描述符或打开另一个描述符到同一个文件,那么我可以使用阻塞I/O和一个非阻塞I/O与另一个.
然而,尝试使用FIFO,似乎不可能同时为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;
}
Run Code Online (Sandbox Code Playgroud)
这让我想到:是否有可能拥有一个非阻塞I/O描述符并阻止I/O描述符到同一个文件,如果是这样,它是否依赖于文件类型(常规文件,FIFO,块特殊文件) ,字符特殊文件,套接字等)?
Jon*_*ler 28
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);
Run Code Online (Sandbox Code Playgroud)
现在fd0_dup和fds [0]都引用相同的打开文件描述(因为dup()),因此fcntl()操作影响了两个文件描述符.
if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... }
Run Code Online (Sandbox Code Playgroud)
因此,这里观察到的行为是POSIX所要求的.