Linux fifo 缓冲采坑

Linux fifo 缓冲采坑

本文记录了我在使用 fifo(命名管道)的过程中由于缓冲踩的坑。

事情的经过是这样的:我有一个 python 脚本,它会实时向标准输出打印数据,现在我想把这些打印到的标准输出数据导入 FIFO 中,并且在另一个 Qt 程序中从 FIFO 读取数据,于是我开始了下述操作。

首先用 mkfifo tmp.fifo 创建了一个 FIFO 文件,然后以下述方式运行我的 python 脚本

python tmp.py > tmp.fifo

另一边创建了一个 Qt 程序打开这个 FIFO 读取数据

    QFile fifo(DEMO_FIFO);
    if (!fifo.open(QIODevice::ReadOnly | QIODevice::Text )) {
        qDebug() << "Open fifo: " << DEMO_FIFO << " error" << endl;
        return -1;
    }
    qDebug() << "Open fifo: " << DEMO_FIFO << " success" << endl;

    char buf[1024];
    while (true) {
        qint64 size = fifo.readLine(buf, sizeof(buf));
        if (size >= 0){
            qDebug() << buf;
        }
    }

两个程序都运行后,出现了一种比较诡异的现象:python 脚本向 FIFO 写入了大量数据后,Qt 程序才会从 readLine() 函数返回,正常情况下应该是 FIFO 写入一行数据,Qt 程序就能够从 FIFO 读出一行数据,但实际情况不是这样,当 FIFO 被写入了大量数据后,才允许从 FIFO 另一端读取数据。

我琢磨了一下午才想到是缓冲区的问题。

C 标准库 IO 函数分为三种缓冲类型:

  • 全缓冲:缓冲区填满,或使用 fflush() 将缓冲区内容刷洗到 IO 设备。
  • 行缓冲:缓冲区填满,或写入 \n,或使用 fflush() 将缓冲区内容刷洗到 IO 设备。
  • 无缓冲:写入字节立即刷洗到 IO 设备。

那么 FIFO 是属于哪一种缓冲区呢?我在 APUE 里找到了下面这几句话:

  • 标准错误是不带缓冲的。
  • 若是指向终端设备的流,则是行缓冲的,否则是全缓冲的。

因此,FIFO 是全缓冲设备,这也解释了为什么上面介绍的 python 脚本将数据打印到标准输出时数据是一行一行的显示,而打印到 FIFO 时,数据只能是一大块一大块的读取。

找到了问题的缘由,我更改了 python 脚本的 print() 函数:

print(f"{json.dumps(data)}");   -->  print(f"{json.dumps(data)}", flush=True);

每写入一行数据,自动刷洗数据,这样就成功解决了问题。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容