【发布时间】:2016-12-01 17:10:19
【问题描述】:
我有两个对象存在于不同的线程中,我试图确定使用的模式是否是线程安全的。
第一个对象是 QObject 派生的,并且存在(在其中创建)主 Qt 线程。该类包含一些应该从 QML 调用的Q_INVOKABLE 方法,一些定义为signals: 的signal*() 方法和一些Emit*()(普通)方法,我用作包装器来发出信号。例如:
void MyQObjectClass::EmitStatus(void) {
emit signalStatusChange(_status);
}
我通常在 QML 中监听这些信号。
第二个对象不是 QObject 派生的,并且存在于第二个线程 (pthread) 中。该线程运行自己的事件循环 (libev) 并调度事件。我不能在这个线程中使用任何与 Qt 相关的东西,因为我需要自定义 libev 事件循环。在这个对象上,我定义了一些 Notify*() 方法,这些方法将通过 libev 发送异步事件以被回调接收。
我需要能够在两个对象/线程之间进行通信,但我不确定如何安全地做到这一点。
实际的设计是让pthread线程对象直接调用不同的Emit*()方法,这样QObject就可以正确地将信息传播到Qt/QML。如果我需要将信息从 Qt/QML 发送到 pthread/libev 对象,我调用(从 Qt 线程)Notify*() 方法。
阅读Accessing QObject Subclasses from Other Threads时,它会说:
QObject 及其所有子类都不是线程安全的。这包括整个事件传递系统。
但随后又指出:
另一方面,您可以从 QThread::run() 实现中安全地发射信号,因为信号发射是线程安全的。
所以我的问题是,上面描述的设计是线程安全的吗?我可以安全地调用myQObject->EmitMySignal(),而后者又会调用emit signalMySignal(),这一切都来自pthread 对象内部?
【问题讨论】:
-
我认为您应该使用
postEvent处理这个问题,而不是像那样直接访问QObject。postEvent是线程安全的,如果您不想或不能使用正常的信号/插槽连接,则专为此目的而设计。 -
发射信号是线程安全的,如前所述。但是,读取成员变量的值不是线程安全的。所以你需要保护对
_status的访问,如果它是从多个线程访问的。从多个线程调用 QObject 方法很容易出错,所以如果你这样做,我建议以下几点: 1. 将方法分为“从其他线程调用”和“普通”方法,并有 不同的命名约定。 2. 以同样的方式划分成员变量,并确保对多线程使用的成员变量的访问进行互斥保护。 3. 查看代码!
标签: c++ multithreading qt