Когда неблокируемый ввод-вывод для stdout включен, правильно ли для ОС включать его и для stdin?
Я заметил неожиданное поведение как в OS X, так и в Linux. Включение неблокирующего ввода / вывода (используя O_NONBLOCK
) для стандартного вывода включает его и для стандартного ввода!
Правильно ли работают эти ОС? Если так, это поведение определяется POSIX? Пожалуйста, укажите мне соответствующую документацию, если это так.
Вот пример программы, которую я использовал для проверки этого:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
int flags = fcntl(STDOUT_FILENO, F_GETFL);
if (argc > 1 && strcmp(argv[1], "1") == 0) {
fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
}
printf("stdout O_NONBLOCK is: %d\n", fcntl(STDOUT_FILENO, F_GETFL) & O_NONBLOCK);
printf("stdin O_NONBLOCK is: %d\n", fcntl(STDIN_FILENO, F_GETFL) & O_NONBLOCK);
return 0;
}
На OS X:
$ clang -o fd-test fd-test.c
$ ./fd-test
stdout O_NONBLOCK is: 0
stdin O_NONBLOCK is: 0
$ ./fd-test 1
stdout O_NONBLOCK is: 4
stdin O_NONBLOCK is: 4
В Linux:
$ gcc -o fd-test fd-test.c
$ ./fd-test
stdout O_NONBLOCK is: 0
stdin O_NONBLOCK is: 0
$ ./fd-test 1
stdout O_NONBLOCK is: 2048
stdin O_NONBLOCK is: 2048
1 ответ
Когда процесс запускается из оболочки, stdin
, stdout
а также stderr
указать на то же описание файла. Это описание файла помечено как O_NONBLOCK
По вашему fcntl(1)
вызов и, следовательно, как ожидается, оба файловых дескриптора помечены как O_NONBLOCK
,
Если вы действительно хотите записать в один и тот же файл два файловых дескриптора, но хотите, чтобы один был помечен как O_NONBLOCK
необходимо создать новое описание файла для того же файла. Если вы знаете имя файла, о котором идет речь, вы можете добиться этого, просто позвонив open()
с желаемым именем файла и флагами. В некоторых операционных системах вы можете найти имя файла с помощью API, специфичного для платформы, например /proc/fd
виртуальная файловая система (многие Unix, включая Linux) или fd2path()
функция из плана 9. Обратитесь к этому вопросу для получения более подробной информации.
Обратите внимание, что просто звонить open("/dev/fd/0", ...)
может работать некорректно, так как возвращает верный указатель на одно и то же описание файла на некоторых платформах.