通过 Qt 信号/槽跨线程传递对象

Posted

技术标签:

【中文标题】通过 Qt 信号/槽跨线程传递对象【英文标题】:Passing object via Qt signal/slot across threads 【发布时间】:2020-05-19 02:23:09 【问题描述】:

我希望在 Qt 的线程之间使用信号/槽机制传递一个对象。由于我将传递一个指向对象的指针,因此在接收方调用对象上的方法是否安全?

根据这个问题question 没有复制对象(所以使用原始对象)。

这样安全吗?还是我在属于另一个线程中的一个线程的对象上执行方法?有没有更好的方法来做到这一点?

(我在这个类中有大约 20 个 getter,所以我不想传递单个变量,而且一些变量实际上也是指向对象的指针)

【问题讨论】:

它本身并不安全,c 你必须通过使用互斥体、原子等使传递的对象线程安全。但即使那样你也可能会遇到生命周期和所有权问题...... 所以信号应该只发送基本类型(而不是对象)? Qt 文档说没问题 (doc.qt.io/qt-5/signalsandslots.html) 但没有提及这些问题。关于如何处理的任何参考 Qt 文档? 信号/槽可以与任何东西一起使用,但是只要您直接(通过指针)共享对象而不是复制它们(通过值/常量引用),通常的多线程同步问题就会应用。信号/插槽只是传递参数的一种方式,它们不控制访问对象后会发生什么。我想说跨线程信号/槽最好与值一起使用,然后实现线程间通信的消息传递编程模型。 @Frank:我认为这是迄今为止最好的答案——如果你回复我会接受 【参考方案1】:

它不一定是安全的——信号和槽可以用来跨越线程边界,所以你可能最终会尝试从另一个线程访问对象。

将调用槽的线程由连接类型决定。请参阅the documentation,但作为示例:

connect(source, SIGNAL(mySignal(QObject*)), destination, SLOT(mySlot(QObject*)), Qt::DirectConnection);

在这种情况下,函数 mySlot() 将从发出 mySignal() 信号的同一线程中调用。如果您的对象没有从与信号发射器相同的线程以外的任何线程访问,则可以正常工作.

connect(source, SIGNAL(mySignal(QObject*)), destination, SLOT(mySlot(QObject*)), Qt::QueuedConnection);

在这种情况下,函数 mySlot() 将被排队,并由destination 对象的事件循环调用。因此,对对象所做的任何事情都将在运行destination 的事件循环的线程中发生。

我个人认为最好坚持将简单值作为参数传递。即使这可行,但如果 QObject 可能从多个线程访问,则需要为 QObject 添加合适的多线程保护。

【讨论】:

问题与 GUI 无关。为什么“基于 GUI 的信号/插槽”可以在另一个线程中正常运行对象,而非 GUI 不能? 对不起,因为 Qt 是一个 gui 工具包,我认为人们会首先遇到这个问题,但你说得对,不一定如此。我更新了答案,希望能更清楚一点【参考方案2】:

首先,在开发多线程应用程序时尝试使用QtConcurrent。 QtConcurrent 命名空间提供了高级 API,使编写多线程程序成为可能,而无需使用低级线程原语,例如互斥锁、读写锁、等待条件或信号量。 之后,安全取决于您的班级成员。如果所有成员都是线程安全的,那么所有成员都将安全运行。

【讨论】:

以上是关于通过 Qt 信号/槽跨线程传递对象的主要内容,如果未能解决你的问题,请参考以下文章

Qt信号和槽对值传递参数和引用传递参数的总结

从主线程发送信号给子线程,子线程里的connect函数怎么个写法

Qt5跨线程信号和槽

Qt::ConnectionType(信号与槽的传递方式)

QT中的信号与事件,多线程

Qt中信号槽形参值传递,引用传递,指针传递的实例及总结