Linux-STDIN_FILENO和STDOUT_FILENO的非阻塞I / O行为很奇怪
作者:互联网
我有以下代码:
void
set_fl(int fd, int flags) /* flags are file status flags to turn on */
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("fcntl F_GETFL error");
val |= flags; /* turn on flags */
if (fcntl(fd, F_SETFL, val) < 0)
err_sys("fcntl F_SETFL error");
}
int
main(void)
{
char buf[BUFSIZ];
set_fl(STDOUT_FILENO, O_NONBLOCK); //set STDOUT_FILENO to nonblock
if(read(STDIN_FILENO, buf, BUFSIZ)==-1) { //read from STDIN_FILENO
printf("something went wrong with read()! %s\n", strerror(errno));
}
}
如您所见,我将STDOUT_FILENO设置为非阻塞模式,但似乎对STDIN_FILENO的读取操作立即完成.为什么?
$./testprog
something went wrong with read()! Resource temporarily unavailable
谢谢
解决方法:
完全正确:读取后立即打印errno和进行错误调用,结果是“资源繁忙”,错误号为11或EAGAIN / EWOULDBLOCK,如以下代码所示:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
int main (void) {
char buf;
fcntl (STDOUT_FILENO, F_SETFL, fcntl (STDOUT_FILENO, F_GETFL, 0) | O_NONBLOCK);
fprintf (stderr, "%5d: ", errno); perror("");
read (STDIN_FILENO, &buf, 1);
fprintf (stderr, "%5d: ", errno); perror("");
}
产生:
0: Success
11: Resource temporarily unavailable
原因是文件描述符具有两种不同类型的标志(请参见详细说明复制文件描述符的部分中的here):
You can duplicate a file descriptor, or allocate another file descriptor that refers to the same open file as the original. Duplicate descriptors share one file position and one set of file status flags (see File Status Flags), but each has its own set of file descriptor flags (see Descriptor Flags).
第一个是file descriptor flags,每个文件描述符确实是唯一的.根据文档,FD_CLOEXEC(在exec上关闭)是当前在这一阵营中唯一的一个.
所有其他标志均为file status flags,并在已重复的文件描述符中共享.这些包括I/O operating modes,例如O_NONBLOCK.
因此,这里发生的是,标准输出文件描述符是从标准输入文件中复制的(顺序无关紧要,只是一个文件与另一个文件被复制的事实),因此在一个文件上设置非阻塞模式会影响所有副本(尽管我尚未确认,但它可能还包括标准错误文件描述符).
在复制的文件描述符上使用阻塞模式,或者在子进程中可能会继承的文件描述符,通常不是一个好主意-这些子进程并不总是善待标准文件的行为(从他们的角度来看).
如果要对单个文件描述符进行更细粒度的控制,请在尝试读取之前考虑使用select检查描述符.
标签:nonblocking,linux 来源: https://codeday.me/bug/20191201/2082162.html