如果在调用 QObject::connect() 之前发出信号,如何避免竞争?

Posted

技术标签:

【中文标题】如果在调用 QObject::connect() 之前发出信号,如何避免竞争?【英文标题】:How to avoid races if a signal is emitted before calling QObject::connect()? 【发布时间】:2021-02-09 23:22:37 【问题描述】:

在 Qt 中,如果信号可以在我连接到它们的大约同一时间发出,如何避免竞争条件?

考虑以下简单示例:

MySignalSender *sender = new MySignalSender(); // starts async operation that emits `fooSignal`
// <-- Possibility (1): `fooSignal` can be emitted here
MySignalReceiver *receiver = new MySignalReceiver();
// <-- Possibility (2): `fooSignal` can be emitted here
QObject::connect(sender, &MySignalSender::fooSignal, receiver, &MySignalReceiver::fooSlot);
// <-- Possibility (3): `fooSignal` can be emitted here or later

由于fooSignal 是从另一个线程发出的,因此调度程序在运行时非确定性地实现了可能性 1-3 的选择。虽然只有在第三种情况下才能实现所需的行为,但在剩下的两种情况下我们会丢失信号,可能会导致死锁或其他一些未定义的行为。

Qt 是否提供一些原子机制来临时暂停来自对象的信号?我知道QObject::blockSignals(),但我的理解是这会完全抑制信号,而不仅仅是将它们推迟一段时间。

提前谢谢你!

【问题讨论】:

【参考方案1】:

一种选择是简单地改变构建发送信号的对象的方式。您可以将对象的构造与异步操作的开始分开。

MySignalSender *sender = new MySignalSender();
MySignalReceiver *receiver = new MySignalReceiver();
QObject::connect(sender, &MySignalSender::fooSignal, receiver, &MySignalReceiver::fooSlot);

sender->startAsyncOperations();

【讨论】:

同意,我会对我控制范围内的对象执行此操作。不幸的是,在调用 Qt 库对象时这是不可能的,例如QNetworkAccessManager::get()。那该怎么办呢? 在那种特定情况下,我总是连接到 QNetworkAccessManager,而不是 QNetworkReply。但我理解你的意思。 哦,太酷了,不知道你能做到。干杯!

以上是关于如果在调用 QObject::connect() 之前发出信号,如何避免竞争?的主要内容,如果未能解决你的问题,请参考以下文章

C++ - Qt QObject::connect 跨类的 GET 请求使用

QObject::connect 在 QRunnable - 控制台

将 lambda 函数作为第三个参数传递给 QObject::connect 时出错

QObject::connect timer with update() 函数

QObject::connect: 没有这样的信号progressbarV::keyReleaseEvent()

QObject::connect 和模板导致问题