如何无阻塞地以只写方式打开FIFO(命名管道)?
解决FIFO只写打开阻塞且非阻塞模式报错的问题
FIFO的默认机制是:仅以O_WRONLY打开时会阻塞,直到有进程以只读方式打开该管道;而添加O_NONBLOCK标志后,若此时无只读进程,open会直接返回ENXIO错误。你遇到的正是这个矛盾场景,以下是符合你“先只写打开再fork”要求的解决方案:
核心思路
先以O_WRONLY | O_NONBLOCK尝试打开FIFO,即便因无读者返回ENXIO错误,也不终止进程,继续执行fork创建子进程。待子进程打开只读FIFO后,父进程再重新以阻塞模式打开只写FIFO,此时因已有读者存在,不会再阻塞。
修改后的代码
#include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> int main() { // 先尝试非阻塞只写打开,仅在非ENXIO错误时退出 int pipe_fd = open("/tmp/ngfifo", O_WRONLY | O_NONBLOCK); if (pipe_fd < 0) { if (errno != ENXIO) { fprintf(stderr, "Opened fifo failed %d\n", errno); return -1; } printf("No reader yet, proceed to fork\n"); } else { close(pipe_fd); // 意外打开成功则先关闭,后续重新打开 } pid_t pid = fork(); if (pid > 0) { // 父进程等待子进程完成只读打开(生产环境建议用信号/管道同步) usleep(1000); // 重新以阻塞模式打开只写FIFO pipe_fd = open("/tmp/ngfifo", O_WRONLY); if (pipe_fd < 0) { fprintf(stderr, "Reopen fifo failed %d\n", errno); wait(NULL); return -1; } printf("begin to write \n"); // 此处添加写操作逻辑 close(pipe_fd); wait(NULL); } else if (pid == 0) { // 子进程打开只读FIFO int read_fd = open("/tmp/ngfifo", O_RDONLY); if (read_fd < 0) { fprintf(stderr, "Open read fifo failed %d\n", errno); return -1; } printf("begin to read \n"); // 此处添加读操作逻辑 close(read_fd); } else { fprintf(stderr, "Fork failed %d\n", errno); return -1; } return 0; }
注意事项
- 代码中用
usleep做简单同步,生产环境建议用信号、匿名管道等更可靠的同步方式,避免父进程在子进程打开FIFO前就重新尝试打开。 - 确保FIFO已通过
mkfifo /tmp/ngfifo命令创建,且权限正确(如mkfifo -m 0666 /tmp/ngfifo避免权限问题)。
内容的提问来源于stack exchange,提问作者Klen
相关产品推荐
相关产品推荐

