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 插槽中的信号失败的主要内容,如果未能解决你的问题,请参考以下文章

Qt4中的信号和插槽 - 不工作

使用 qt 中的信号/插槽更新 gui [关闭]

Qt:如何将不同类的静态信号连接到插槽?

Qt Jambi (Qt4Dotnet):区分插槽中的信号发射器

如何将信号和插槽与 qt 中的另一个对象连接 - 已解决

在Qt中通过信号和插槽系统传递变量[关闭]