代码之家  ›  专栏  ›  技术社区  ›  shylent

QT槽信号故障

  •  2
  • shylent  · 技术社区  · 14 年前

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

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

    如果使用者端的处理由于任何原因失败,那么队列的处理必须停止,因为继续进行没有意义。

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

    我可以想到两种方法:

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

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

    • 生产者和使用者属于同一线程
    • 生产者和使用者属于不同的线程

    简言之,我必须确保,如果消费者报告错误,就不会发生其他处理。

    正如你可能猜到的,我还不太熟悉qt的成语。

    2 回复  |  直到 14 年前
        1
  •  2
  •   photo_tom    14 年前

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

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

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

    在跨线程传输信号/插槽时,qt默认情况下采用queuedconnection。这里发生的事情很复杂。序列是

    1. 发出的信号由QapplicationCare接收。
    2. core对插槽接收线程的数据空间中的参数进行深度复制。
    3. 控制返回到发出信号的功能。
    4. 核心根据事件队列调用槽。

    既然知道了这一点,回到您原来的问题,如何知道时隙函数何时停止处理?Qt没有一个我知道如何传递这些信息的习惯用法。但是Qt信号/插槽的习惯用法是,信号线程不应该知道插槽如何工作或连接类型是什么。

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

    1. 结果标志。至少应包括“未启动”、“已完成”、“已完成但有错误”和“功能已中止”的状态。“函数已中止”标志将在try/catch块的catch块中设置。
    2. 基于 QDateTime 设置为发出信号时的当前日期/时间。如果信令线程使用此值来确定使用线程是否完全失败。

    使用这种方法- -调用线程没有理由直接了解信号线程。 -如果从单线程或多线程开始,这个结构中没有需要更改的内容。

    希望这对你的问题有帮助。这是我们商店目前使用的方法。

        2
  •  1
  •   Paul Michalik    14 年前

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