qt 插槽中的信号失败
Posted
技术标签:
【中文标题】qt 插槽中的信号失败【英文标题】:Signaling failure in qt slots 【发布时间】:2010-09-26 10:43:06 【问题描述】:我有一个“生产者”对象,它遍历一些数据并根据队列中的下一个数据项发出各种信号。
这些信号中的每一个一次最多由一个“消费者”对象处理(在将生产者的信号附加到另一个消费者之前,它会注意断开其插槽)。
如果消费者端的处理由于某种原因失败,队列的处理必须停止,因为继续它没有意义。
让生产者知道由于特殊情况不需要进一步处理的最佳方式是什么?由于消费者有一个指向生产者的指针,我想,可能有多种方式,只是我不确定它们是否是竞争条件安全的(我不知道我是否可以依赖于发出/处理了哪些信号)。
我能想到的两种方法:
在生产者上设置一个标志,可以在下一次迭代中检查它,以便它知道是时候停止了 在消费者(以及生产者的相应插槽)上注册一个信号,当处理应该停止时将发出该信号我想知道这些解决方案在以下情况下是否可行:
生产者和消费者属于同一个线程 生产者和消费者属于不同的线程简而言之,我必须绝对确保,如果消费者报告错误,则不会发生额外的处理。
您可能已经猜到了,我对 Qt 的这些方面的习语还不是很熟悉。
【问题讨论】:
【参考方案1】:您有几个相互关联的问题。
对我来说,最重要的问题与使用线程的信号/插槽有关。
当在单个线程中使用信号/槽时,Qt 默认采用AutoConnection 或“直接”连接。在直接连接模式下,信号/插槽的行为几乎与回调函数完全一样。这意味着发出信号的函数本质上是执行子程序调用。
当跨线程传输信号/槽时,Qt 默认采用 QueuedConnection。这里发生的事情很复杂。序列是 -
-
QApplicationCore 接收到发出的信号。
核心在槽接收线程的数据空间中制作参数的深层副本。
控制权返回给发出信号的函数。
核心根据事件队列调用槽位。
知道了这一点,回到你原来的问题,如何知道槽函数何时停止处理? Qt 没有我知道如何将这些信息传回的习语。但是 Qt signal/slots 的习惯用法是,信号线程应该对 slot 的功能或连接类型是什么一无所知。
所以我的建议是通过指向要处理的数据的指针传递数据。在数据中,我会添加两个字段 -
-
结果标志。至少,这应包括“未开始”、“已完成”、“已完成但有错误”和“功能中止”的状态。 “函数中止”标志将设置在 try/catch 块的 catch 块中。
基于QDateTime 的看门狗定时器字段设置为发出信号时的当前日期/时间。如果信号线程使用这个值来确定消费线程是否已经完全失败。
使用这种方法 - - 调用线程没有理由必须直接了解信令线程。 - 如果您从单线程或多线程开始,此结构中无需更改任何内容。
希望这对您的问题有所帮助。这是我们目前在我们的商店中使用的方法。
【讨论】:
【参考方案2】:这个成语不是 qt 特有的。我恳求您已经提出的第二种可能性的变体。但是,您不需要为答案注册信号/插槽对,只需传递将由生产者处理的回调,但可能在消费者的线程上。例如:
// this answer might arrive on Consumer's thread...
void Producer::ProcessAnswer(bool pShouldStop)
// mShouldStopProcessing is shared among threads
if (mShouldStopProcessing) return;
if (pShouldStop)
// double checking pattern...
if (!mShouldStopProcessing)
Lock lock;
if (!mShouldStopProcessing)
// this notifies producer to stop processing
mShouldStopProcessing = true;
void Producer::ProcessData()
for (DataContainer::iterator tCurrent = mData.begin();
tCurrent != mData.end();
++tCurrent)
if (mShouldStopProcessing) break;
else
// emit signal here:
OnDataProcessing
(*tCurrent, std::bind(std::mem_fn(&Producer::ProcessAnswer), this));
在消费者方面,您需要:
void ProcessData(Data& pData, std::function<void (bool)> pCallback)
// process data here...
bool tResult = //...;
pCallback(tResult);
【讨论】:
以上是关于qt 插槽中的信号失败的主要内容,如果未能解决你的问题,请参考以下文章