从 C++ 中的多个线程调用 Qt 中小部件类的信号函数是不是安全?

Posted

技术标签:

【中文标题】从 C++ 中的多个线程调用 Qt 中小部件类的信号函数是不是安全?【英文标题】:Is it safe to call a signal function of a widget class in Qt from multiple threads in C++?从 C++ 中的多个线程调用 Qt 中小部件类的信号函数是否安全? 【发布时间】:2013-08-28 00:17:13 【问题描述】:

同时从多个线程调用小部件的信号函数是否安全?当多个线程同时调用某个小部件的信号时,Qt 会使用某种内部互斥体来提供其自身数据结构的安全性吗?

据我了解,这是安全的,同时 N 个信号函数调用将导致 N 个已连接信号的连续调用。

我说的对吗?

附: 调用信号函数的线程是用 boost 创建的。我认为,这对于这个问题并不重要。我不能使用其他线程,因为这些线程不仅与 GUI 相关,而且它们服务于程序的许多部分。

【问题讨论】:

【参考方案1】:

简而言之,您不调用信号,而是发出信号。然后 Qt 在内部处理信号连接到的任何插槽的触发。

根据连接类型,发出信号并让它触发槽可能是线程安全的,也可能不是线程安全的。

阅读here了解更多信息。

而且我认为 boost 创建的线程会是一个问题——信号/槽机制依赖于 QThread 和 QObject 的基础设施。如果您可以使用 QThread 而不是 boost 线程,它可能会更好、更简单。

【讨论】:

"emit" 它是一个简单的宏,它被什么都取代了。所以“发射”==“呼叫”。 您提供的链接说默认连接类型的行为类似于“排队连接”,以防信号从与接收对象具有亲和力(属于)的线程不同的线程发出。所以,看来我不必考虑这个了。【参考方案2】:

如果您使用 QThreads,则完全没有问题,因为 Qt 会自动管理这种情况。所以你(可能的)问题来自于使用 boost 线程。

但是,有一个简单的解决方案:确保使用Qt::QueuedConnection 连接信号和插槽。这会将一个事件发布到 Widget 线程的事件循环中并执行该线程中的插槽。 (当对象存在于不同的线程中时,这就是使用 QThreads 自动执行的操作)。

请注意,在这种情况下,槽执行将是异步的。如果您需要同步执行槽(即所有槽必须在发出信号的代码继续之前完成),请使用Qt::BlockingQueuedConnection

【讨论】:

【参考方案3】:

这取决于连接。如果连接是直接的,则发射线程将用于将信号传递到已连接的插槽。这安全吗?这取决于插槽。特别是,QWidget 上的插槽无法处理此问题。如果连接排队,则存储信号。接收器对象有一个关联的 QThread,该线程有一个事件循环,并且该事件循环会将存储的信号传递给接收器。

您的问题描述了排队连接的行为。这是一个有效的可能性。 Qt 事件循环是线程安全的。向它传递信号和从中调用槽都得到了适当的保护。由于每个接收器只有一个 QThread,这意味着排队的信号是按顺序传递的。

【讨论】:

此页面qt-project.org/doc/qt-4.8/… 表示,如果信号从与接收对象具有亲和力(属于)的线程不同的线程发出,则默认连接类型的行为类似于“排队连接”。

以上是关于从 C++ 中的多个线程调用 Qt 中小部件类的信号函数是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

QGridLayout 限制中的多个小部件

Qt入门教程QObject篇重入性和线程安全

Qt入门教程QObject篇重入性和线程安全

Qt:: 如何消除 qmainwindow 中小部件和工具栏之间的间隙

如何在 C++ 中运行具有仅调用线程的函数的类的多个对象?

从 Qt 中的信号调用成员函数的问题