【问题标题】:Signaling failure in qt slotsqt 插槽中的信号失败
【发布时间】:2010-09-26 10:43:06
【问题描述】:

我有一个“生产者”对象,它遍历一些数据并根据队列中的下一个数据项发出各种信号。

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

如果消费者端的处理由于某种原因失败,队列的处理必须停止,因为继续它没有意义。

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

我能想到的两种方法:

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

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

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

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

您可能已经猜到了,我对 Qt 的这些方面的习语还不是很熟悉。

【问题讨论】:

    标签: c++ qt qt4 signals-slots


    【解决方案1】:

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

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

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

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

    1. QApplicationCore 接收到发出的信号。
    2. 核心在槽接收线程的数据空间中制作参数的深层副本。
    3. 控制权返回给发出信号的函数。
    4. 核心根据事件队列调用槽位。

    知道了这一点,回到你原来的问题,如何知道槽函数何时停止处理? Qt 没有我知道如何将这些信息传回的习语。但是 Qt signal/slots 的习惯用法是,信号线程应该对 slot 的功能或连接类型是什么一无所知。

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

    1. 结果标志。至少,这应包括“未开始”、“已完成”、“已完成但有错误”和“功能中止”的状态。 “函数中止”标志将设置在 try/catch 块的 catch 块中。
    2. 基于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);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-11
        • 2020-10-01
        • 2017-08-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-08
        • 2016-10-07
        相关资源
        最近更新 更多