You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:47:07