【问题标题】:qnetworkaccessmanager QNetworkReply - race condition?qnetworkaccessmanager QNetworkReply - 竞争条件?
【发布时间】:2014-08-08 01:20:59
【问题描述】:

我有这个与 QT 相关的问题。 QNetworkAccessManager::get() 返回 QNetworkReply 指针。然后我可以连接到它的完成槽:

QNetworkReply* r = nam->get(url);
connect(r, SIGNAL(finished()),
            this, SLOT(_finishedThisReply()));

这似乎是做事的正确方法,特别是,使用这种方法,您可以同时使用相同的 QNetworkAccessManager 对象发出请求。但是,我们这里没有竞争条件吗?如果在完成 get 和调用 connect 之间发送了完成的信号怎么办?还是 QT 保证不会发生这种情况?我在 QT 文档中找不到任何关于它的信息。

【问题讨论】:

    标签: qt network-programming qt5


    【解决方案1】:

    由于您可以完全控制您运行的线程中发生的事情,因此您的代码在此处运行,因此不会出现竞争条件。

    当然,网络访问管理器的内部可能正在另一个线程中运行。假设在QNetworkManager 的实现中发生了以下情况:

    Thread A: QNetworkReply* r = nam->get(url);
    Thread B: emit r->finished();
    Thread A: connect(r, SIGNAL(finished()), ...);
    

    那确实是个问题。唉,实现可以做其他事情:

    Thread A: QNetworkReply* r = nam->get(url);
    Thread B: QMetaObject::invokeMethod(r, "finished");
              // equivalent to QCoreApplication::postEvent(r, new QMetaCallEvent(...))
    Thread A: connect(r, SIGNAL(finished()), ...);
              ...
    

    这里 signal 在回复的线程中同步发出。这与第一个变体形成对比,第一个变体是异步发出信号的。

    最终,线程 A 的控制权返回到事件循环,跨线程方法调用以QMetaCallEvent 的形式发送到r,发出信号。

    我正在简化,但QNetworkReply 的语义是第二个正确变体的语义。它“正常工作”。没有竞争,即使网络访问管理器的实现是在单独的线程中运行。

    【讨论】:

    • 我认为 QNetworkAccessManager 确实使用了额外的线程,以免阻塞主 GUI 线程。如果我理解正确,您是说 QNetworkAccessManager 需要将 finished() 事件发布到主线程,并且在主事件循环中处理此请求之前,我可以安全地订阅信号?
    • @Andre 是的,发布插槽调用与发布信号调用之间存在关键区别。发布的调用是一个信号,一旦您将控制权返回给事件循环,它就会被您的线程拾取。如果网。经理。发布了一个插槽调用(或发出一个信号),那么您的插槽将不会被调用,因为在信号发射时您的插槽尚未连接。后一种情况就是你担心的比赛。
    • 好吧,明确一点,信号发射(发送到当前连接的槽)必须通过事件循环中的主线程来完成,对吗?
    • 是的。如果发射发生在另一个线程中,那么您将参加比赛。
    • 嗯,你知道 QNetworkReply 是否在另一个线程上发布它吗?
    猜你喜欢
    • 2022-01-23
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多