qt 插槽中的信令失败

发布于 2024-09-24 15:39:18 字数 574 浏览 1 评论 0原文

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

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

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

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

我能想到的两种方法:

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

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

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

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

正如您可能猜到的那样,我还不太熟悉 Qt 的此类事物的习惯用法。

I have a 'producer' object, that steps through some data and emits various signals depending on what data item is next in the queue.

Each of those signals are processed by at most one 'consumer' object at a time (it takes care to disconnect its slots before attaching the producer's signals to the other consumer).

If the processing on the consumer side fails for whatever reason, the processing of the queue must stop, as there is no point in going ahead with it.

What would be the optimal way of letting the producer know, that no further processing is needed because of an exceptional condition? Since the consumers have a pointer to the producer, I would imagine, that there could be multiple ways, its just that I am not sure if they are race-condition-safe (I don't know if I can depend on the order in which signals are emitted / processed).

Two ways I can think of:

  • set a flag on the producer, that can be checked on the next iteration so that it will know that it is time to stop
  • register a signal on the consumer (and a corresponding slot on the producer), that will be emitted when processing should be halted

I am wondering if these solutions are viable at all in the following scenarios:

  • producer and consumer(s) belong to the same thread
  • producer and consumer(s) belong to different threads

In short, I have to make absolutely sure, that no additional processing will happen if the consumer reports an error.

As you can probably guess, I am not very familiar with Qt's idioms for such things yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鸵鸟症 2024-10-01 15:39:18

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

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

当在单个线程中使用信号/槽时,Qt 默认情况下假定 自动连接 或“直接”连接。在直接连接模式下,信号/槽的行为几乎与回调函数完全相同。这意味着发出信号的函数本质上执行子程序调用。

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

  1. 发出的信号由 QApplicationCore 接收。
  2. 核心在槽接收线程的数据空间中对参数进行深度复制。
  3. 控制权返回到发出信号的函数。
  4. 核心在可以基于事件队列的情况下调用插槽。

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

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

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

使用这种方法 -
- 调用线程没有必要直接了解信号线程。
- 如果您从单线程或多线程过渡,此结构中没有任何内容需要更改。

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

You have a couple of inter-related questions.

To me, the most important question is related to signal/slots working with threading.

When using signal/slots within a single thread, Qt by default assumes a AutoConnection or "direct" connect. In direct connect mode, signal/slots acts almost exactly like a callback function. Meaning that the function emitting the signal essentially executes a subroutine call.

When transferring signal/slots across threads, Qt by default assumes a QueuedConnection by default. What happeans here is complicated. Sequence is -

  1. Emitted Signal is recieved by the QApplicationCore.
  2. Core makes a deep copy of the arguments in the data space of the slot receiving thread.
  3. Control is returned to function that emitted the signal.
  4. Core calls the slot when it can based on the event queue.

So knowing this, back to your original question, how to know when the slot function has stopped processing? Qt doesn't have an idiom that I'm aware of how to pass this information back. But the idiom with Qt signal/slots is the signalling thread should know nothing about how the slot function or how what the connection type is.

So my recommendation would be to pass the data via a pointer to the data to be processed. In the data, I would add two fields -

  1. A result flag. At a minimum, this should include states for "Not Started", "Completed", "Completed w/errors" and "Function Aborted". The "Function Aborted" flag would be set in the catch block of a try/catch block.
  2. A watchdog timer field based on QDateTime set to current date/time when signal is emitted. If the signalling thread uses this value to determine if the consuming thread has completely failed.

Using this approach -
- There is no reason that the calling thread has to have any direct knowledge of the signalling thread.
- There is nothing in this structure that needs to change if you go from single threaded or multiple threaded.

Hope this helps with your problem. This is the approach we are currently using in our shop.

巨坚强 2024-10-01 15:39:18

该习惯用法不是 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);
}

The idiom is not qt-specific. I'd plead for the variant of the second possibility you have already proposed. However, you don't need to register a signal/slot pair for the answer, just pass a callback which will be processed by the producer, but possibly on consumer's thread. For example:

    // 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));
                }
        }
    }

On Consumer's side you'd need:

void ProcessData(Data& pData, std::function<void (bool)> pCallback) {
    // process data here...
    bool tResult = //...; 
    pCallback(tResult);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文