非阻塞在pipe道上读取

人们可以在pipe道上进行非阻塞I / O吗? fcntl无法设置O_NONBLOCK。 Linux编程接口的页面918包括一个表“从pipe道或FIFO(p)读取n个字节的语义”。 该表列出了一列标题为O_NONBLOCK的pipe道和FIFO的行为? 这意味着你可以在pipe道上设置O_NONBLOCK标志。 它是否正确? 下面的代码无法设置标志,fcntl(2)虽然不报告错误。

#include <fcntl.h> #include <sys/wait.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #define SLEEP 1 int main(int argc, char *argv[]) { pid_t childPid; int pfd[2]; int nread, flags; int c = 'a'; setbuf(stdout, NULL); if (pipe(pfd) == -1) { printf("error: pipe"); exit(EXIT_FAILURE); } switch (childPid = fork()) { case -1: printf("error: fork"); exit(EXIT_FAILURE); case 0: /* child */ if (close(pfd[0]) == -1) { printf("child: close pfd read"); exit(EXIT_FAILURE); } sleep(SLEEP); _exit(EXIT_SUCCESS); default: break; /* parent falls through */ } if (close(pfd[1]) == -1) { printf("parent: close pipe write"); exit(EXIT_FAILURE); } flags = fcntl(pfd[0], F_GETFD); flags |= O_NONBLOCK; if (fcntl(pfd[0], F_SETFD, flags)) perror("fcntl"); /* verify flags set correctly */ flags = fcntl(pfd[0], F_GETFD); if (!(flags & O_NONBLOCK)) { printf("failed to set O_NONBLOCK\n"); exit(EXIT_FAILURE); } wait(NULL); exit(EXIT_SUCCESS); } 

没有什么特别的管道和O_NONBLOCK。 以下示例按预期工作。 我没有检查每个调用的每个retval,使这个例子更具可读性。 真实世界的应用程序必须执行检查。

 #include <unistd.h> #include <stdio.h> #include <string.h> #include <fcntl.h> int main() { int fds[2]; pid_t pid; char buf[100]; pipe(fds); pid = fork(); if ( pid ) { while (1 ) { memcpy( buf, "abcdefghi\0",10); write( fds[1], buf, 10); sleep(2); } } else { int retval = fcntl( fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK); printf("Ret from fcntl: %d\n", retval); while (1) { ssize_t r=read( fds[0], buf, 10 ); printf("read: %d\n", r); if ( r > 0 ) { printf("Buffer: %s\n", buf); } else { printf("Read nothing\n"); perror("Error was"); sleep(1); } } } } 

写完我的例子后,我检查你的代码,发现:

 flags = fcntl(pfd[0], F_GETFD); flags |= O_NONBLOCK; if (fcntl(pfd[0], F_SETFD, flags)) 

请将F_SETFD更改为F_SETFL以及get操作。 您不会更改file descriptor flagsfile descriptor status flags 🙂

man 3 fcntl

文件描述符标志以下命令处理与文件描述符相关的标志。 目前,只有一个这样的标志被定义:FD_CLOEXEC,关闭执行标志。 如果FD_CLOEXEC位为0,则文件描述符将在execve(2)之间保持打开状态,否则它将被关闭。

文件状态标志每个打开的文件描述都有一些相关的状态标志,由open(2)初始化,并可能由fcntl()修改。 重复的文件描述符(使用dup(2),fcntl(F_DUPFD),fork(2)等)引用相同的打开文件描述,因此共享相同的文件状态标志。

F_SETFL(int)将文件状态标志设置为由arg指定的值。 arg中的文件访问模式(O_RDONLY,O_WRONLY,O_RDWR)和文件创建标志(即O_CREAT,O_EXCL,O_NOCTTY,O_TRUNC)被忽略。 在Linux上,此命令只能更改O_APPEND,O_ASYNC,O_DIRECT,O_NOATIME和O_NONBLOCK标志。 不可能改变O_DSYNC和O_SYNC标志; 见下面的BUGS。