【问题标题】:Could this code potentially run into an infinite loop?这段代码可能会陷入无限循环吗?
【发布时间】:2012-05-13 08:01:08
【问题描述】:

这个Qt代码会不会陷入死循环?

QNetworkAccessManager m;
QNetworkReply *reply = m.get(QNetworkRequest(QUrl("http://www.example.org/")));
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
qDebug() << reply->readAll();
delete reply;

这基本上是一种显示网页内容的“同步”方式。

我没有观察到使用它的任何问题,但我考虑了以下情况:

  • replyfinished 信号在创建事件循环之前发出,并在finishedquit 之间建立信号槽连接
  • 不会从该点发出任何信号,因此永远不会触发quit
  • loop.exec() 会不断循环

有可能发生这种情况,还是我不了解 Qt 事件循环的工作原理?

【问题讨论】:

    标签: c++ qt concurrency


    【解决方案1】:

    虽然 Qt 执行您自己的代码(例如上面的代码),但它不能处理新信号和调用槽。在您的方法执行时发出的每个信号都将在稍后处理。如果你想在你的方法中间强制处理信号,你可以调用QCoreApplication::processEvents在你当前的事件循环中处理信号,或者QEventLoop::exec在另一个循环中处理。

    所以这段代码是安全的。如果信号来得太快,它将在事件队列中等待。

    如果您发出一个信号并且有插槽使用Qt::DirectConnection 连接到此信号,这些插槽将立即执行。但这不符合你的情况。 Qt 必须在发出信号之前执行一些内部代码。当您的方法正在执行时,它无法执行此代码。只有一个线程,只有一个调用栈。

    请注意,当您使用 Qt 线程时,事件循环的行为会更加复杂。

    【讨论】:

    • “稍后处理”。不正确。 “当发出信号时,连接到它的插槽通常会立即执行”参见Qt documentation。我认为您混淆了信号和事件。在同一线程中发出的信号会立即使用QMetaObject::activate->qt_static_metacall 进行处理,因此信号处理不当会导致无限递归和堆栈溢出。
    • 是的,我写过这个。但这只有在此代码发出信号时才会发生。但是如果当前执行的代码与 QNetworkReply 无关,它(或其嵌套的函数调用)就不能发出 QNetworkReply 的信号。并且没有其他人可以同时发出这个信号。
    【解决方案2】:

    在运行loop.exec() 之前,您可以检查reply-&gt;isFinished()。如果是,就不要执行循环。

    【讨论】:

    • 错了,QNetworkAccessManager::get 在进入事件循环之前甚至不会开始处理创建的请求
    猜你喜欢
    • 2022-08-19
    • 2020-06-09
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    相关资源
    最近更新 更多