STDIN_FILENO和STDOUT_FILENO的非阻塞I / O行为很奇怪

时间:2012-03-13 01:03:44

标签: linux nonblocking

我有以下代码:

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

由于

1 个答案:

答案 0 :(得分:3)

这是完全正确的:在读取后立即执行errnoperror调用打印导致“资源忙”且错误编号为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):

  

您可以复制文件描述符,或者分配引用与原始文件相同的打开文件的另一个文件描述符。重复描述符共享一个文件位置和一组文件状态标志(请参阅文件状态标志),但每个都有自己的一组文件描述符标志(请参阅Descriptor Flags)。

第一个是file descriptor flags,这些文件描述符确实是唯一的。根据文件,FD_CLOEXEC(关闭exec)是目前在这个阵营中唯一的人。

所有其他标志都是file status flags,并且在已复制的文件descritors之间共享。其中包括I/O operating modes,例如O_NONBLOCK

所以,这里发生的事情是标准输出文件描述符是从标准输入文件中复制的(顺序不相关,只是一个是从另一个重复的事实),所以在一个上设置非阻塞模式影响所有重复项(也可能包括标准错误文件描述符,但我还没有确认)。

对于复制的文件描述符上的阻塞模式以及可能由子进程继承的文件描述符,通常不是一个好主意 - 这些子进程并不总是善于使用它们的标准行为不端(从他们的角度来看)。

如果您想要对单个文件描述符进行更细粒度的控制,请考虑在尝试读取之前使用select检查描述符