我有一个相当简单的应用程序,当我调用QEventLoop :: exec时,在某些条件下似乎死锁。应用程序在两种情况下调用此函数:
在这两种情况下都用于以下上下文(只是一个http查询,真的没什么特别的):
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;
}
以下是尝试调用时发生的情况:
...
#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),然后我看到这样的行:
#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
...
有人可以向我解释我在这里做错了什么吗?
答案 0 :(得分:0)
http://qt-project.org/doc/qt-4.8/qeventloop.html#exec
int QEventLoop :: exec(ProcessEventsFlags flags = AllEvents)进入 主事件循环并等待直到调用exit()。返回 传递给exit()的值。
exec()是QT事件处理的表示,并且始终是阻塞调用,直到当前Thread返回exit()。这允许主循环exec()之外的线程使用QT信号和插槽而不会发生冲突。
您应该使用Header文件中定义的自己的处理插槽来连接您的finished()调用。
如果您想使用信号和插槽并使用QOBJECT Makro,请不要忘记从QObject(或任何其他QT对象)继承每个类。
答案 1 :(得分:0)
您正在运行两个事件循环。第二个事件循环不会阻塞第一个事件循环 - 它只是阻止当前方法,因此处理无法返回到第一个事件循环。但是,当数据到达套接字时,事件将被触发,您的方法将再次运行。对我来说似乎唯一的解决方案是在syncHttp
方法中将您的设计更改为无阻塞地工作,并使用信号和方法重新连接此方法的整个交互。槽。
至于exec
成语,来自the link you've provided:
警告:对于测试用例,此方法效果很好。对于实际应用,请避免使用它。最好将想要等待的功能分成两部分,处理信号是一个单独的插槽。
如果你有一个事件驱动的应用程序(通常你有,如果你正在使用Qt)并且突然需要像这样阻止 - 这意味着存在设计问题。
答案 2 :(得分:0)
您正试图以阻止方式使用QNetworkManager
和QNetworkReply
,但这并不是设计用的。
请考虑使用QTcpSocket
或重新设计程序以使用异步机制。