调用open()函数操作FIFO时出现无限阻塞问题的技术问询
FIFO open()调用无限阻塞的原因与解决方案
先看一下你提供的代码:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <iostream> #include <string.h> int main(){ int fd; size_t size; char name[]="aaa.fifо"; // 注意:这里最后一个字符是俄文的"о",不是英文的"o",建议修正 umask(0) ; if (mknod(name, S_IFIFO | 0666, 0) < 0){ printf("Can't create FIFO\n"); _exit(-1); } if ((fd = open(name, O_WRONLY)) < 0){ printf("Can't open FIFO for writing\n"); _exit(-1); } char message[60]; while(true){ message[0] = 0; std::cin.clear(); std::cin >> message; if(!strcmp(message,"exit")) { printf("Exit to programm\n"); break; } size = write(fd, message, 60); if (size < strlen(message)) { printf("Can't write all string to FIFO\n"); _exit(-1); } } close(fd); return 0; }
问题根源:FIFO的默认打开行为
你遇到的open()无限阻塞是FIFO(命名管道)的设计特性:当你以O_WRONLY模式打开FIFO时,内核会一直阻塞这个调用,直到有另一个进程以O_RDONLY模式打开同一个FIFO。这是为了保证数据不会被写入到没有读者的管道中(避免数据丢失)。
你的代码只实现了写端,但没有对应的读端进程,所以open()会一直等待读端连接,自然无法继续执行后续逻辑。
解决方案
这里有两种常用的解决方式,根据你的实际需求选择:
1. 先启动一个读进程(推荐的标准用法)
FIFO是用于进程间通信的,所以正常使用需要读写两端都存在。你可以:
- 写一个简单的读端程序,比如:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main(){ int fd; char name[]="aaa.fifo"; // 注意修正为英文的"o" char buffer[60]; if ((fd = open(name, O_RDONLY)) < 0){ printf("Can't open FIFO for reading\n"); _exit(-1); } while(read(fd, buffer, 60) > 0){ printf("Received: %s\n", buffer); } close(fd); return 0; }
- 或者直接用命令行工具临时作为读端:在终端执行
cat < aaa.fifo(注意要和你的FIFO名字一致,记得修正名字里的俄文字符)。
启动读进程后,再运行你的写进程,open()就会立即返回,程序可以正常执行。
2. 打开时添加O_NONBLOCK标志(非阻塞模式)
如果你不需要等待读端,或者想自己处理无读端的情况,可以在open()时添加O_NONBLOCK标志,让调用立即返回:
if ((fd = open(name, O_WRONLY | O_NONBLOCK)) < 0){ printf("Can't open FIFO for writing\n"); _exit(-1); }
但要注意:此时如果没有读端,write()会失败(返回-1,errno设置为EPIPE),所以你需要在write()后增加错误处理逻辑,避免程序直接退出。
额外注意事项
你的代码里FIFO名字是"aaa.fifо",最后一个字符是俄文的"о"(不是英文的"o"),这会导致你用普通命令行工具(比如ls)查看时,名字可能显示异常,甚至读进程找不到这个FIFO。建议把它改成英文的"aaa.fifo",避免不必要的问题。
内容的提问来源于stack exchange,提问作者Naxal
相关产品推荐
相关产品推荐

