阻塞读取管道的调用

Blocking call to read a pipe

我正在使用 Qt 创建一个显示 GUI 并接受来自管道的输入的小型应用程序。

如果管道未创建(或者,据我所知,如果没有编写器),对 fopen 的调用会阻塞,甚至认为它应该被调用show() 函数后,UI 未显示。

如何显示UI,然后调用fopen和相关代码?我不在乎 fopen 是否阻塞,只要我的 window 事先出现在屏幕上即可。

我试过使用 connect(this, SIGNAL(window_loaded), this, SLOT(setupListener())); 之类的东西,但行为保持不变。

有什么提示吗?谢谢!

main.cpp

#include <QApplication>

#include "metadataWindow.h"

#include <sys/time.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    metadataWindow window;
    window.showFullScreen();
    window.setupListener();

    return app.exec();
}

metadataWindow.cpp

metadataWindow::metadataWindow(QWidget *parent) : QWidget(parent)
{
    this->setupUI(); // not shown here, but just basic QLabel stuff
}

void metadataWindow::setupListener()
{
    const char *metadata_file = "/tmp/my-pipe-file";

    // vvvvv This here is blocking vvvvvv
    FILE *fd = fopen(metadata_file, "r");

    pipe = new QTextStream(fd);

    streamReader = new QSocketNotifier(fileno(fd), QSocketNotifier::Read, qApp);
    QObject::connect(streamReader, SIGNAL(activated(int)), this, SLOT(onData()));
    streamReader->setEnabled(true);
}

X 是一种异步的、基于消息的协议。 X 显示服务器和 X 客户端程序不断地交换消息。 X 客户端程序不只是按下某种虚拟按钮,绘制它的 window,然后收工,直到它想要更改 window 上的某些内容。显示服务器和客户端程序之间唯一没有消息交换的情况是显示上完全没有任何反应。没有鼠标指针移动。没有任何显示 activity。

显示 window 的任务按顺序涉及多个步骤。实际的 window 对象本身被创建。所有 subwindows 都已创建。所有 windows 都已映射。映射 window 导致 X 服务器向客户端程序发送一系列暴露事件,作为响应,客户端程序负责呈现 window 的暴露部分。所有这些都是作为 X 显示服务器和 X 客户端程序之间交换的数百条消息序列完成的。

这就是 QApplication::exec() 调用的作用。它进入 Qt 的主事件循环,Qt 库相应地处理 X 显示事件。在事件循环运行之前,不会有任何可见的显示变化。

当使用像 X/Qt 这样基于事件的基础设施时,正确的设计模式也是一种基于事件的方法。您有两个基本选项。

  1. 在新线程中执行您的阻塞应用程序逻辑,独立于进入 Qt 事件循环的主执行线程。这绕过了和回避了符合事件驱动设计模式的需要,并使得可以做几乎普通程序会做的事情,而不会打扰 Qt。

  2. 也为您自己的代码使用具有非阻塞文件描述符的事件驱动模型。无法使用 fopen() 库调用。相反,管道将以非阻塞模式 open()ed,当文件系统管道的另一端打开时,管道将可选择写入。阅读 open()poll() 的手册页以获取更多信息。最后阅读 Qt 的 QSocketNotifier class 文档,它解释了如何让 Qt 库也监视您自己的文件描述符上的事件,作为其主事件循环的一部分,并调用您的代码来处理读写它们的任务。

当然,同时使用执行线程和套接字通知程序的混合方法也是可能的。重要的一点是了解进程应该如何正确工作,并且永远不要编写任何阻塞 Qt 主事件循环的代码。