неблокирующее поведение ввода-вывода странно для STDIN_FILENO и STDOUT_FILENO - PullRequest
3 голосов
/ 13 марта 2012

У меня есть следующий код:

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 Ответ

3 голосов
/ 13 марта 2012

Совершенно верно: выполнение печати errno и вызова perror сразу после чтения приводит к «ресурсу занято» и к ошибке с номером 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

Причина в том, что файловые дескрипторы имеют два различных типа флагов (см. здесь в разделе, подробно описывающем дублирование файловых дескрипторов):

Вы можете продублировать дескриптор файла или выделить другой дескриптор файла, который ссылается на тот же открытый файл, что и оригинал. Дублирующиеся дескрипторы совместно используют одну позицию файла и один набор флагов состояния файла (см. Флаги состояния файла), но каждый имеет свой собственный набор флагов дескриптора файла (см. Флаги дескриптора).

Первый - это флаги дескриптора файла , и они действительно уникальны для каждого дескриптора файла. Согласно документации, FD_CLOEXEC (рядом с exec) является единственным в настоящее время в этом лагере.

Все остальные флаги являются флагами состояния файла и совместно используются дескрипторами файлов, которые были продублированы. К ним относятся режимы ввода-вывода , такие как O_NONBLOCK.

Итак, что здесь происходит, так это то, что стандартный дескриптор выходного файла был продублирован из стандартного входного (порядок не имеет значения, только тот факт, что один был продублирован из другого), так что установка режима неблокирования для одного влияет на все дубликаты (и это, вероятно, также включало бы стандартный дескриптор файла ошибок, хотя я не подтвердил это).

Обычно не стоит разбираться с режимом блокировки дубликатов файловых дескрипторов или файловыми дескрипторами, которые, вероятно, будут наследоваться подпроцессами - эти подпроцессы не всегда любезны иметь свой стандарт файлы плохо себя ведут (с их точки зрения).

Если вы хотите более детальный контроль над отдельными файловыми дескрипторами, рассмотрите возможность использования select для проверки дескрипторов перед попыткой чтения.

...