2014-06-17 34 views
3

我有这个QT相关的问题。 QNetworkAccessManager :: get()返回QNetworkReply指针。然后我可以连接到它的光洁度插槽:qnetworkaccessmanager QNetworkReply - 比赛条件?

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

这似乎做的事情以正确的方式,特别是,使用这种方法,你可以有相同的QNetworkAccessManager对象同时请求。但是,我们在这里没有竞争条件吗?如果在完成获取和呼叫之间连接完成的信号已发送?或者QT保证这不会发生?我在QT文档中找不到任何有关它的信息。

回答

3

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

当然,网络访问管理器的内部可能在另一个线程中运行。假设在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()), ...); 
      ... 

这里一个信号发出同步,得到的答复的线程中。这与第一种异步发射信号形成了对比。

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

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

+0

我想QNetworkAccessManager不会使用额外的线程为了不阻止主要的GUI线程。如果我正确理解了你的话,你说QNetworkAccessManager需要将finished()事件发布到主线程上,并且直到在主事件循环中处理完这个请求,我才可以安全地订阅这个信号? – Andre

+0

@Andre是的,发布槽位呼叫与发布信号呼叫之间存在着重要的区别。发布的调用是一个信号,一旦你将控制权返回给事件循环,它就会被你的线程拾取。如果网。经理。发布了一个插槽呼叫(或*发出*信号),然后您的插槽将不会被呼叫,因为在信号发射时您的插槽尚未连接。后一种情况是你担心的比赛。 –

+0

好的,很明显,信号发射(发送到当前连接的插槽)必须通过事件循环中的主线程完成,对吗? – Andre