qt时隙中的信令失败

时间:2010-09-26 10:43:06

标签: c++ qt qt4 signals-slots

我有一个'生产者'对象,它会逐步调查一些数据,并根据队列中下一个数据项发出各种信号。

这些信号中的每一个一次最多由一个“消费者”对象处理(在将生产者的信号附加到另一个消费者之前,需要断开其插槽)。

如果消费者方面的处理因任何原因失败,则必须停止对队列的处理,因为没有必要继续处理它。

让生产者知道的最佳方法是什么,由于特殊条件,不需要进一步处理?由于消费者有一个指向生产者的指针,我想,可能有多种方式,只是我不确定它们是否是竞争条件安全的(我不知道我是否可以依赖于订单发射/处理哪些信号。

我能想到的两种方式:

  • 在生产者上设置一个标志,可以在下一次迭代中检查,以便它知道是时候停止了
  • 在消费者(以及生产者的相应位置)上注册信号,该信号将在处理暂停时发出

我想知道在以下情况下这些解决方案是否可行:

  • 生产者和消费者属于同一个主题
  • 生产者和消费者属于不同的线程

简而言之,我必须绝对确定,如果消费者报告错误,则不会进行额外的处理。

正如你可能猜到的那样,我对这些事情的Qt习语并不十分熟悉。

2 个答案:

答案 0 :(得分:2)

你有几个相互关联的问题。

对我而言,最重要的问题与使用线程的信号/插槽有关。

在单个线程中使用信号/插槽时,Qt默认采用AutoConnection或“直接”连接。在直接连接模式下,信号/插槽几乎完全像回调函数。这意味着发出信号的函数基本上执行子程序调用。

跨线程传输信号/插槽时,默认情况下Qt默认采用QueuedConnection。这里发生的事情很复杂。顺序是 -

  1. QApplicationCore收到发出的信号。
  2. Core在插槽接收线程的数据空间中生成参数的深层副本。
  3. 控制返回到发出信号的功能。
  4. Core可以基于事件队列调用插槽。
  5. 知道这一点,回到原来的问题,如何知道插槽功能何时停止处理? Qt没有一个成语,我知道如何传回这些信息。但是Qt信号/槽的成语是信令线程应该对槽功能如何或连接类型是什么一无所知。

    所以我的建议是通过指向要处理的数据的指针传递数据。在数据中,我会添加两个字段 -

    1. 结果标志。至少应包括“未启动”,“已完成”,“已完成错误”和“功能已中止”的状态。 “函数已中止”标志将在try / catch块的catch块中设置。
    2. 基于QDateTime的看门狗定时器字段设置为发出信号时的当前日期/时间。如果信令线程使用此值来确定消耗线程是否已完全失败。
    3. 使用这种方法 -   - 没有理由调用线程必须具有信令线程的任何直接知识。   - 如果你从单线程或多线程转发,这个结构中什么都不需要改变。

      希望这有助于解决您的问题。这是我们目前在我们的商店中使用的方法。

答案 1 :(得分:1)

这个成语不是特定于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);
}