首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Qt:调用QEventLoop::exec后的死锁

Qt:调用QEventLoop::exec后的死锁
EN

Stack Overflow用户
提问于 2014-08-22 19:33:54
回答 3查看 4K关注 0票数 1

我有一个相当简单的应用程序,当我调用QEventLoop::exec时,这个应用程序在某些条件下似乎处于死锁状态。应用程序在两个场景中调用此函数:

  • 当某些数据到达套接字上时
  • 计时器事件

在这两种情况下,它都在以下上下文中使用(只是一个http查询,实际上没有什么特殊的查询):

代码语言:javascript
复制
QNetworkReply::NetworkError HttpGetMessagesStrategy::syncHttp(const QUrl url, QByteArray &dst) const
{
    QNetworkRequest request(url);
    request.setRawHeader("Cache-Control", "no-cache");

    QNetworkAccessManager mgr;
    QEventLoop eventLoop;
    QObject::connect(&mgr, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));
    QNetworkReply *reply = mgr.get(request);
    if (reply == NULL) {
        return QNetworkReply::UnknownNetworkError;
    }

    eventLoop.exec();

    QNetworkReply::NetworkError error = reply->error();
    if (error == QNetworkReply::NoError) {
        dst += reply->readAll();
    }
    delete reply;

    return error;
}

下面是当它试图调用它时发生的情况:

代码语言:javascript
复制
...    
#56 0x0000003404b57cdc in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /usr/lib64/libQtCore.so.4
#57 0x0000003404b804a2 in ?? () from /usr/lib64/libQtCore.so.4
#58 0x0000003404b7d928 in ?? () from /usr/lib64/libQtCore.so.4
#59 0x00000033fba38f0e in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#60 0x00000033fba3c938 in ?? () from /lib64/libglib-2.0.so.0
#61 0x00000033fba3ca3a in g_main_context_iteration () from /lib64/libglib-2.0.so.0
#62 0x0000003404b7d5f3 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQtCore.so.4
#63 0x0000003404b56722 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQtCore.so.4
#64 0x0000003404b569ec in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQtCore.so.4
#65 0x00007f41c1b4eec7 in HttpGetMessagesStrategy::syncHttp (this=<value optimized out>, url=<value optimized out>, dst=...) at HttpGetMessagesStrategy.cpp:49
#70 0x000000000040e57c in DevicePlugin::timerEvent (this=0x1267390, event=0x7fff902bb5f0) at DevicePlugin.cpp:250
#71 0x0000003404b6698e in QObject::event(QEvent*) () from /usr/lib64/libQtCore.so.4
#72 0x0000003404b57cdc in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /usr/lib64/libQtCore.so.4
...

可以看到,它没有等待HTTP请求的响应,而是选择了另一个事件并开始处理它。因此,在我的应用程序停止之前,我在当前线程中得到了大量的帧(746),然后我看到了这样的行:

代码语言:javascript
复制
#0  0x00000033faa0efe0 in __pause_nocancel () from /lib64/libpthread.so.0
#1  0x00000033faa0917b in __pthread_mutex_lock_full () from /lib64/libpthread.so.0
#2  0x0000003404a702a3 in ?? () from /usr/lib64/libQtCore.so.4
#3  0x0000003404a6cd95 in QMutex::lock() () from /usr/lib64/libQtCore.so.4
#4  0x0000003404b57952 in QCoreApplication::postEvent(QObject*, QEvent*, int) () from /usr/lib64/libQtCore.so.4
#5  0x000000000040e293 in DevicePlugin::destroyConnection (this=0x1267390, c=0x1a85fb0) at DevicePlugin.cpp:194
#6  0x000000000040e5b6 in DevicePlugin::timerEvent (this=0x1267390, event=0x7fff902b9230) at DevicePlugin.cpp:254
#7  0x0000003404b6698e in QObject::event(QEvent*) () from /usr/lib64/libQtCore.so.4
#8  0x0000003404b57cdc in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /usr/lib64/libQtCore.so.4
...

有人能解释一下我在这里做错了什么吗?

EN

回答 3

Stack Overflow用户

发布于 2014-08-22 20:21:43

http://qt-project.org/doc/qt-4.8/qeventloop.html#exec

int::exec( ProcessEventsFlags标志= AllEvents )进入主事件循环并等待直到exit()被调用。返回传递给exit()的值。

exec()是QT事件处理的表示形式,它始终是一个阻塞调用,直到当前线程使用exit()返回为止。这允许主循环exec()外部的线程使用QT信号和插槽,而不会产生冲突。

您应该将finished()调用与头文件中定义的自己的处理槽连接起来。

如果您想要使用信号和插槽并使用QObject,请不要忘记从QOBJECT (或任何其他QT对象)继承每个类。

票数 0
EN

Stack Overflow用户

发布于 2014-08-22 21:48:33

您有两个事件循环正在运行。第二个事件循环不阻止第一个事件循环-它只是阻塞当前方法,因此处理不能返回到第一个事件循环。但是,当数据到达套接字时,事件将被触发,您的方法将再次运行。在我看来,唯一的解决方案是改变您的设计,使其在不阻塞syncHttp方法的情况下工作,并使用信号和插槽重新连接与此方法的整个交互。

至于exec的成语,来自你提供的链接

警告:对于测试用例,这种方法运行良好。对于真正的应用程序,避免使用它。最好将想要等待的函数拆分成两个,并且处理信号是一个单独的插槽。

如果您有一个事件驱动的应用程序(通常是这样的,如果您使用的是Qt),并且突然需要这样的阻塞--这意味着存在设计问题。

票数 0
EN

Stack Overflow用户

发布于 2014-08-24 07:48:21

您正在尝试以阻塞的方式使用QNetworkManagerQNetworkReply,而这并不是设计的目的。

考虑使用QTcpSocket,或者重新设计程序以使用异步机制。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25454330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档