如何避免Linux下FIFO写入程序阻塞?
如何避免FIFO写入时的阻塞,实现持续写入?
我在Linux终端通过 mkfifo myFIFO 创建了FIFO文件,并编写了如下C++代码:
#include <iostream> using namespace std; #include <stdio.h> int main(int argc, char** argv) { FILE* fp = fopen("/tmp/myFIFO", "w"); fprintf(fp, "Hello, world!\n"); fclose(fp); cout << "!!!Hello World!!!" << endl; return 0; }
但该程序会阻塞直到其他进程读取myFIFO,请问如何避免这种阻塞?我希望这段代码能持续处理并写入。
解决思路与方案
FIFO(命名管道)的默认行为就是写入端会阻塞直到有读端打开它——这是它的设计特性,用来保证数据不会被丢弃。要实现非阻塞的持续写入,你可以试试下面几种方法:
1. 以非阻塞模式打开FIFO
fopen()没办法直接设置非阻塞标志,所以我们改用底层的open()系统调用,指定O_WRONLY | O_NONBLOCK参数,这样打开FIFO时就不会阻塞,后续写入操作也会是非阻塞的(注意:如果没有读端连接,写入会失败,需要处理这个错误)。
修改后的代码示例:
#include <iostream> #include <fcntl.h> // 提供O_WRONLY、O_NONBLOCK等标志 #include <unistd.h> // 提供write()、close()系统调用 #include <cstring> // 提供strlen() #include <errno.h> // 提供errno错误码 using namespace std; int main(int argc, char** argv) { // 以非阻塞模式打开FIFO写端 int fd = open("/tmp/myFIFO", O_WRONLY | O_NONBLOCK); if (fd == -1) { perror("Failed to open FIFO"); return 1; } const char* msg = "Hello, world!\n"; ssize_t bytes_written = write(fd, msg, strlen(msg)); if (bytes_written == -1) { if (errno == EAGAIN) { // EAGAIN表示当前没有读端连接,可选择稍后重试 cout << "No reader connected yet. Try again later." << endl; } else { perror("Failed to write to FIFO"); } } else { cout << "Successfully wrote " << bytes_written << " bytes to FIFO." << endl; } close(fd); cout << "!!!Hello World!!!" << endl; return 0; }
2. 提前启动一个后台读进程
如果你的场景允许,最简单的方式是提前开一个持续读取FIFO的后台进程,这样写入端永远不会因为没有读端而阻塞。比如在终端执行:
cat /tmp/myFIFO &
这个cat进程会一直挂在后台读取FIFO内容,你的写入程序就能正常运行,甚至可以持续循环写入数据。
3. 多线程+非阻塞实现持续写入
如果需要程序自身处理持续写入的逻辑,可以把写入操作放到单独的线程里,主线程继续处理其他任务。线程内部循环尝试写入,遇到无读端的情况就等待重试。
示例代码:
#include <iostream> #include <fcntl.h> #include <unistd.h> #include <cstring> #include <thread> #include <chrono> #include <errno.h> using namespace std; void continuous_write() { int fd = open("/tmp/myFIFO", O_WRONLY | O_NONBLOCK); if (fd == -1) { perror("Failed to open FIFO"); return; } int msg_count = 0; while (msg_count < 10) { // 模拟写入10条消息 char buffer[64]; snprintf(buffer, sizeof(buffer), "Message %d: Hello from FIFO!\n", ++msg_count); ssize_t bytes_written = write(fd, buffer, strlen(buffer)); if (bytes_written == -1) { if (errno == EAGAIN) { cout << "Waiting for reader... Retrying in 1 second." << endl; this_thread::sleep_for(chrono::seconds(1)); continue; } else { perror("Write failed"); break; } } cout << "Sent: " << buffer; this_thread::sleep_for(chrono::seconds(1)); } close(fd); } int main() { // 启动写入线程 thread write_thread(continuous_write); // 主线程可以并行处理其他任务 cout << "Main thread is handling other business..." << endl; // 等待写入线程完成 write_thread.join(); cout << "!!!Hello World!!!" << endl; return 0; }
重要注意事项
- 当以非阻塞模式写入时,如果没有读端,
write()会返回-1且errno=EAGAIN,这是正常的临时错误,不要直接终止程序,可以选择重试。 - 如果读端突然关闭,写入端会收到
SIGPIPE信号,默认会导致程序崩溃。你可以通过signal(SIGPIPE, SIG_IGN)忽略这个信号,或者捕获它做优雅处理。
内容的提问来源于stack exchange,提问作者hildogjr
相关产品推荐
相关产品推荐

