Qt 网络请求的条件变量
Posted
技术标签:
【中文标题】Qt 网络请求的条件变量【英文标题】:Condition variables with Qt network requests 【发布时间】:2016-03-20 21:30:01 【问题描述】:我有一个应用程序,我在其中使用 Qt 的 QNetwork* 类进行一些“类似同步”的调用。从网上各种来源改编的代码如下:
QNetworkRequest request("http://www.somedomain.com");
QNetworkReply* pReply = _manager->get(request);
// A not-so-great-solution to wait for the request, but works
QEventLoop loop;
QObject::connect(pReply, SIGNAL(finished()), &loop, SLOT(quit()), Qt::DirectConnection);
loop.exec(QEventLoop::ExcludeUserInputEvents);
// Now the pReply object has what I want, yay!
我知道这是一个 hack,所以我实现了这个。我开始想知道是否可以改用 C++ 的条件变量来实现类似的效果。我尝试这样做的代码如下所示:
QNetworkRequest request("http://www.somedomain.com");
QNetworkReply* pReply = _manager->get(request);
QObject::connect(pReply, &QNetworkReply::finished,
[this]()
std::unique_lock<std::mutex> lock(_requestMutex);
_requestCV.notify_one();
);
std::unique_lock<std::mutex> lock(_requestMutex);
_requestCV.wait(lock, [this, pReply]()
return pReply->isFinished();
);
这是我第一次尝试条件变量,所以我不完全确定我是否正确使用它们(_requestCV
当然是本例中的条件变量)。但真正让我困惑的是 QNetworkReply::finished lambda 永远不会执行。在第一个示例中,finished() 事件似乎几乎立即触发,并且 QNetworkReply 具有我所期望的一切。为什么在第二个示例中从未调用 pReply 的 finished() 事件?
注意:我知道很多人对同步网络调用有强烈的感觉,尤其是 Qt 的模型,它显然是为异步使用而设计的。但是,这不是我有兴趣讨论这个问题的内容。谢谢。
【问题讨论】:
【参考方案1】:但真正让我感到困惑的是 QNetworkReply::finished lambda 从不执行。
您正在阻塞线程的事件循环,而这个事件循环应该传递您的finished
signal。没有事件循环,没有信号。
注意:我知道很多人对同步有强烈的感觉 网络调用,尤其是显然设计的 Qt 模型 异步使用。
嗯,你已经举了一个很好的例子来说明人们有这种感觉的原因。
【讨论】:
我不是只阻塞当前线程吗?如果这段代码本身在不同的线程上执行,事件循环是否仍会被阻塞? @Addy 看起来你阻塞了同一个线程,在那里你调用 QNetworkAccessManager::get(),所以要么阻塞它的线程,要么你从不同的线程调用 get(我不认为它是线程安全的......)。 @Addy "如果这段代码本身在不同的线程上执行,事件循环是否仍会被阻塞?"* 每个线程都有它的事件循环,但这就是重点:你阻塞的循环是应该传递你的信号。 @Addy 好的 - 我将在答案中添加该位以澄清以上是关于Qt 网络请求的条件变量的主要内容,如果未能解决你的问题,请参考以下文章
QT实现CSDN上传资源管理助手Demo之请求网络图片SVG并显示
我的QT Creator学习笔记(三十四)——网络编程之HTTP与FTP