在stdin
上执行函数fcntl
时,我遇到了一个问题,当我将stdin
FD状态标志设置为O_NONBLOCK
,它工作正常,但在一个副作用。 stdout和stderr的状态标志也变成了O_NONBLOCK
。
我调查了函数fcntl
, SYSCALL_DEFINE3
和do_fcntl
的源代码,但没有得到任何帮助。 另外stackoverflow或谷歌。 我认为它可能与内核或glibc实现有关。
我的电脑是x86_64上的Ubuntu 12.04,安装了gcc 4.6.3。
int flag = 0; int value = O_NONBLOCK; int fd = open("./tmp", O_RDONLY); if(-1 == (flag = fcntl(fd, F_GETFL))) fprintf(stdout, "%d:%s\n", errno, strerror(errno)); flag = fcntl(stdin->_fileno, F_GETFL); flag = fcntl(stderr->_fileno, F_GETFL); if(-1 == (flag = fcntl(stdout->_fileno, F_GETFL))) fprintf(stdout, "%d:%s\n", errno, strerror(errno)); flag = fcntl(stdout->_fileno, F_SETFL, flag | O_NONBLOCK); flag = fcntl(fd, F_GETFL); flag = fcntl(stdin->_fileno, F_GETFL); flag = fcntl(stdout->_fileno, F_GETFL); flag = fcntl(stderr->_fileno, F_GETFL); flag = fcntl(stdin->_fileno, F_SETFL, flag | O_APPEND); flag = fcntl(fd, F_GETFL); flag = fcntl(stdin->_fileno, F_GETFL); flag = fcntl(stdout->_fileno, F_GETFL); flag = fcntl(stderr->_fileno, F_GETFL); close(fd);
这是我的这个问题的代码。
登录过程(或终端打开过程)传统上使用的“技巧”之一是以文件描述符0(标准输入)的读写模式打开终端,然后复制文件描述符1和2(标准输出和标准错误)。 这意味着:
fcntl()
的F_GETFL和F_SETFL选项与打开的文件描述有关。 fcntl()
的F_GETFD和F_SETFD选项与文件描述符有关。
一个给定的打开的文件描述可能有多个文件描述符,可能在单个进程(在dup()
或dup2()
)或跨进程(由于fork()
)。
从Jonathan的回答来看,下面是一些更为清晰的代码:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> void show_nonblock_status(void) { char streams[3][7] = {"stdin", "stdout", "stderr"}; for ( int i = 0; i < 3; ++i ) { int flag = fcntl(i, F_GETFL); if ( flag == -1 ) { perror("error getting flags"); exit(EXIT_FAILURE); } if ( flag & O_NONBLOCK ) { printf("O_NONBLOCK is set for %s\n", streams[i]); } else { printf("O_NONBLOCK is not set for %s\n", streams[i]); } } } int main(void) { show_nonblock_status(); int flag = fcntl(1, F_GETFL); if ( flag == -1 ) { perror("error getting flags"); exit(EXIT_FAILURE); } flag = fcntl(1, F_SETFL, flag | O_NONBLOCK); if ( flag == -1 ) { perror("error getting flags"); exit(EXIT_FAILURE); } show_nonblock_status(); return 0; }
在各种用途下提供以下输出:
paul@local:~/src/c/scratch$ ./fct O_NONBLOCK is not set for stdin O_NONBLOCK is not set for stdout O_NONBLOCK is not set for stderr O_NONBLOCK is set for stdin O_NONBLOCK is set for stdout O_NONBLOCK is set for stderr paul@local:~/src/c/scratch$ cat testfile | ./fct O_NONBLOCK is not set for stdin O_NONBLOCK is not set for stdout O_NONBLOCK is not set for stderr O_NONBLOCK is not set for stdin O_NONBLOCK is set for stdout O_NONBLOCK is set for stderr paul@local:~/src/c/scratch$ cat testfile | ./fct 2>/dev/null O_NONBLOCK is not set for stdin O_NONBLOCK is not set for stdout O_NONBLOCK is not set for stderr O_NONBLOCK is not set for stdin O_NONBLOCK is set for stdout O_NONBLOCK is not set for stderr paul@local:~/src/c/scratch$
在第一种情况下,文件描述是相同的,所以三个都设置了O_NONBLOCK
。
在第二种情况下,将文件传送到stdin
,以便对stdout
和stderr
具有不同的文件描述,两者都设置了O_NONBLOCK
。
在第三种情况下,文件被传送到stdin
,并且stderr
被重定向到/dev/null
,因此所有3个文件描述是不同的,并且O_NONBLOCK
仅被设置为stdout
。