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 从不执行。

您正在阻塞线程的事件循环,而这个事件循环应该传递您的finishedsignal。没有事件循环,没有信号。

注意:我知道很多人对同步有强烈的感觉 网络调用,尤其是显然设计的 Qt 模型 异步使用。

嗯,你已经举了一个很好的例子来说明人们有这种感觉的原因。

【讨论】:

我不是只阻塞当前线程吗?如果这段代码本身在不同的线程上执行,事件循环是否仍会被阻塞? @Addy 看起来你阻塞了同一个线程,在那里你调用 QNetworkAccessManager::get(),所以要么阻塞它的线程,要么你从不同的线程调用 get(我不认为它是线程安全的......)。 @Addy "如果这段代码本身在不同的线程上执行,事件循环是否仍会被阻塞?"* 每个线程都有它的事件循环,但这就是重点:你阻塞的循环是应该传递你的信号。 @Addy 好的 - 我将在答案中添加该位以澄清

以上是关于Qt 网络请求的条件变量的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 绑定到特定接口/IP 中发出网络请求?

QT实现CSDN上传资源管理助手Demo之请求网络图片SVG并显示

Qt设置阻塞式网络请求,和超时处理

我的QT Creator学习笔记(三十四)——网络编程之HTTP与FTP

我的QT Creator学习笔记(三十四)——网络编程之HTTP与FTP

第九课Qt之高级网络操作(HTTP/FTP快速上手)