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

QSocketNotifier监听FIFO时持续触发信号问题排查

解决QSocketNotifier监听FIFO时持续触发信号导致CPU占用100%的问题

咱们来拆解下你遇到的问题:当FIFO的写端关闭后,代码会陷入无限触发activated信号的循环,直接把CPU拉满。核心原因是非阻塞模式下,FIFO所有写端关闭时,read()会返回0(表示EOF),而QSocketNotifier会把这种情况判定为文件描述符“可读”,所以会持续发送信号。你的代码只判断了rl <=0就break,但没区分是EOF还是暂时无数据,导致每次信号触发都跑一遍循环,然后Notifier立刻又触发,形成死循环。

具体修复方案

你需要在读取逻辑里区分read()返回值的不同情况,针对性处理:

  • 当read()返回0:说明所有写端已关闭,必须禁用QSocketNotifier,阻止它继续触发信号;如果之后还需要接收新写入,可能需要重新打开FIFO并创建新的Notifier。
  • 当read()返回-1:检查错误码,若是EAGAIN或EWOULDBLOCK,说明当前无数据可读,正常break即可;其他错误则需关闭FIFO并清理Notifier资源。

修改后的代码示例

// create the FIFO
if(!mkfifo(SERIAL_FIFO, 0600)) {
    // nonblocking open (even open itself would block until a first write)
    in_fifo = ::open(SERIAL_FIFO, O_RDONLY | O_NONBLOCK);
    if(in_fifo >= 0) {
        // create notifier
        in_fifo_notifier = new QSocketNotifier(in_fifo, QSocketNotifier::Read, this);
        connect(&*in_fifo_notifier, &QSocketNotifier::activated, this, [this](QSocketDescriptor /*socket*/, QSocketNotifier::Type /*type*/){
            // copy all the available data
            char buf[4096];
            for(;;) {
                ssize_t rl = ::read(in_fifo, buf, sizeof(buf));
                if(rl > 0) {
                    ::write(out_fd, buf, rl);
                } else if(rl == 0) {
                    // EOF: all writers closed, disable notifier to stop spamming
                    in_fifo_notifier->setEnabled(false);
                    // 如果之后需要重新监听,可以在这里记录状态,后续重新打开FIFO
                    break;
                } else {
                    // read error, check if it's just no data available
                    if(errno != EAGAIN && errno != EWOULDBLOCK) {
                        // real error, clean up
                        in_fifo_notifier->setEnabled(false);
                        ::close(in_fifo);
                        in_fifo = -1;
                        delete in_fifo_notifier;
                        in_fifo_notifier = nullptr;
                    }
                    break;
                }
            }
        });
    }
}

额外注意事项

  • 如果需要支持写端关闭后重新打开的场景,不能一直持有当前的FIFO文件描述符(它会一直处于可读返回EOF的状态),需在收到EOF后关闭描述符,再通过定时检查或文件系统监控事件重新打开FIFO并创建新的QSocketNotifier。
  • 对象销毁时,记得检查并关闭in_fifo、删除in_fifo_notifier,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Matteo Italia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 13:22:55