Qt:使用QEventLoop等待信号,如果信号发射得太早怎么办?

Qt: Waiting for a signal using QEventLoop, what if the signal is emitted too early?

我正在开发一个小型客户端-服务器应用程序。客户端发送一个查询,必须等待一个答案。我认为最方便的方法是使用 QEventLoop:

connect(&parser, SIGNAL(answer_received()), this, SLOT(react_to_answer()));
...
...
QEventLoop loop;
connect(&parser, SIGNAL(answer_received()), &loop, SLOT(quit()));
this.sendQuery();
loop.exec();

目前这对我有用,但是如果信号 answer_received() 发出得非常快,甚至在调用 loop.exec() 之前,会发生什么情况?我的应用程序会永远卡在 QEventLoop 中吗?

谢谢!

根据您的代码,您遇到问题的唯一方法是在调用 loop.exec() 之前发出 answer_received() 信号。这相当于说 answer_received() 在调用 this.sendQuery();.

期间发出

在您的情况下,这不太可能发生,因为您依赖 server/client 交互并且您可能使用某种 QNetworkAccessManagerQSocket。如果是这种情况,QNetworkAccessManager/QSocket 将不会发出 readyRead()finished() 信号,直到您进入事件循环。

但是,在更一般的情况下,如果 answer_received() 可以从 this.sendQuery() 发出,您必须更改代码:

  1. 您可以让连接排队。这样,即使 answer_received()this.sendQuery() 期间发出,插槽也不会被调用,直到您进入事件循环。

    connect(&parser, SIGNAL(answer_received()), &loop, SLOT(quit()), Qt::QueuedConnection);
    
  2. 您可以确保在 this.sendQuery() 期间永远不会发出 answer_received()。这样做的方法是使用 0ms QTimer,它会在事件队列中的所有事件都被处理后立即触发,即在 loop.exec()

    期间

    替换:

    emit answer_received();
    

    作者:

    QTimer::singleShot(0, this, *receiver, &MyClass::answer_received);