Qt扫盲-QObject对象和线程
创始人
2024-05-19 15:52:44
0

QObject对象和线程

  • 一、概述
  • 二、QObjectReentrant性
  • 三、每个线程事件的循环
  • 四、从其他线程访问QObject的子类
  • 五、跨线程的信号和槽函数

一、概述

QThread继承QObject。QThread它发出信号来指示线程开始或结束执行,还提供了一些任务槽。

Qobject可以在多个线程中使用,发出信号调用其他线程中的槽函数,并将事件发送给“活动”在其他线程中的对象。这是可能的,因为每个线程都允许有自己的事件循环。

二、QObjectReentrant性

QObject是 Reentrant 的。什么是Reentrant 可以参考 Reentrant 。

QObject的大多数非gui子类,如QTimer、QTcpSocket、QUdpSocket和QProcess,也是Reentrant的,这使得从多个线程同时使用这些类成为可能。注意,这些类被设计为在单个线程中创建和使用;在一个线程中创建对象并在另一个线程中调用它的函数并不能保证有效。有三个约束需要注意。

  1. QObject的子对象必须始终在父对象创建的线程中创建。这意味着,除了其他事情之外,永远不应该将QThread对象(This)作为在线程中创建的对象的父对象(因为QThread对象本身是在另一个线程中创建的)。
  2. 事件驱动对象只能在单个线程中使用。具体来说,这适用于定时器机制和网络模块。例如,不能在非对象所属线程的线程中启动定时器或连接套接字。
  3. 在删除QThread之前,必须确保在线程中创建的所有对象都被删除。这可以通过在run()实现中在栈上创建对象来轻松实现。

虽然QObject是Reentrant的,但GUI类,尤其是QWidget及其所有子类,是不Reentrant的。它们只能在主线程中使用。如前所述,QCoreApplication::exec()也必须从该线程调用。

实际上,在主线程之外的其他线程中使用GUI类是不可能的,通过将耗时的操作放在单独的工作线程中,并在工作线程完成时在主线程的屏幕上显示结果,可以很容易地解决这个问题

一般来说,在QApplication之前创建qobject是不支持的,并且可能会在退出时导致奇怪的崩溃,这取决于平台。这意味着也不支持QObject的静态实例。一个结构合理的单线程或多线程应用程序应该让QApplication是第一个被创建,最后被销毁的QObject。

三、每个线程事件的循环

每个线程可以有自己的事件循环。初始线程使用QCoreApplication::exec()启动它的事件循环,或者对于单对话框GUI应用程序,有时使用QDialog::exec()。其他线程可以使用QThread::exec()启动事件循环。与QCoreApplication类似,QThread提供了一个exit(int)函数和一个quit()槽函数。

线程中的事件循环使得线程可以使用某些需要事件循环出现的非gui Qt类(如QTimer、QTcpSocket和QProcess)。它还可以将任何线程的信号连接到特定线程的槽函数。将在下面的跨线程信号和槽中更详细地解释。
在这里插入图片描述
QObject实例位于创建它的线程中。该对象的事件由该线程的事件循环分发。QObject所在的线程可以通过QObject::thread()获得。

QObject::moveToThread()函数更改对象及其子对象的线程亲和性(如果对象有父对象,则不能移动)。
如果不是从拥有该QObject的线程(或以其他方式访问该对象)上调用delete,则是不安全的,除非你保证该对象在那一刻没有处理事件。相反,使用QObject::deleteLater(),将发送一个DeferredDelete事件,对象线程的事件循环最终将接收该事件。默认情况下,拥有QObject的线程是创建QObject的线程,但在调用QObject::moveToThread()之后就不是这样了。

如果没有事件循环运行,事件就不会传递给对象。例如,如果您在线程中创建了一个QTimer对象,但从未调用exec(),那么QTimer将永远不会发出timeout()信号。调用deleteLater()也不能正常工作。(这些限制也适用于主线程。)
你可以使用线程安全函数QCoreApplication::postEvent()在任何时间手动向任何线程中的任何对象发送事件。事件将由创建对象的线程的事件循环自动分派。

所有线程都支持事件过滤器,但限制是监视对象必须与被监视对象在同一个线程中。类似地,QCoreApplication::sendEvent()(与postEvent()不同)只能用于将事件分发给函数调用所在线程中的对象。

四、从其他线程访问QObject的子类

QObject及其所有子类都不是线程安全的。这包括整个事件传递系统。重要的是要记住,当你从另一个线程访问对象时,事件循环可能会将事件传递给你的QObject子类。

如果在不在当前线程中的QObject子类上调用函数,并且该对象可能会接收事件,则必须使用互斥量保护对QObject子类内部数据的所有访问;否则,您可能会遇到崩溃或其他不希望出现的行为。

与其他对象一样,QThread对象存在于创建对象的线程中——而不是在调用QThread::run()时创建的线程中。在你的QThread子类中提供槽函数通常是不安全的,除非你用互斥量保护成员变量。
另一方面,你可以安全地从QThread::run()实现中发射信号,因为信号发射是线程安全的。

五、跨线程的信号和槽函数

Qt支持以下信号槽连接类型。
信号槽函数的一个参数会指定跨线程之类的,也就是最后一个默认参数 Qt::ConnectionType

QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

参数选项及解释:

  • Auto Connection (默认):如果信号在接收对象具有父子关系的线程中发出,那么行为与直接连接相同。否则,行为与排队连接相同。”

  • Direct Connection:当信号发出时,立即调用槽函数。槽函数在发射器的线程中执行,而不一定是接收器的线程。

  • Queued Connection:当控制返回到接收方线程的事件循环时,调用槽函数。槽函数在接收者的线程中执行。

  • Blocking Queued Connection:排队连接与队列连接一样调用槽函数,但当前线程阻塞直到槽函数返回。
    注意:使用此类型连接同一线程中的对象将导致死锁。

  • Unique Connection:连接行为与自动连接相同,但只有在不复制现有连接时才建立连接。也就是说,如果同一个信号已经连接到同一对对象的同一个槽函数,那么连接就不会建立,connect()返回false。

连接类型可以通过给connect()传递一个额外的参数来指定。请注意,如果事件循环在接收方的线程中运行,那么当发送方和接收方处于不同的线程中时,使用直接连接是不安全的,原因与在另一个线程中的对象上调用任何函数都是不安全的。

QObject::connect()本身是线程安全的。

相关内容

热门资讯

安卓子系统windows11,... 你知道吗?最近科技圈可是炸开了锅,因为安卓子系统在Windows 11上的兼容性成了大家热议的话题。...
电脑里怎么下载安卓系统,电脑端... 你有没有想过,你的电脑里也能装上安卓系统呢?没错,就是那个让你手机不离手的安卓!今天,就让我来带你一...
索尼相机魔改安卓系统,魔改系统... 你知道吗?最近在摄影圈里掀起了一股热潮,那就是索尼相机魔改安卓系统。这可不是一般的改装,而是让这些专...
安卓系统哪家的最流畅,安卓系统... 你有没有想过,为什么你的手机有时候像蜗牛一样慢吞吞的,而别人的手机却能像风一样快?这背后,其实就是安...
安卓最新系统4.42,深度解析... 你有没有发现,你的安卓手机最近是不是有点儿不一样了?没错,就是那个一直在默默更新的安卓最新系统4.4...
android和安卓什么系统最... 你有没有想过,你的安卓手机到底是用的是什么系统呢?是不是有时候觉得手机卡顿,运行缓慢,其实跟这个系统...
平板装安卓xp系统好,探索复古... 你有没有想过,把安卓系统装到平板上,再配上XP系统,这会是怎样一番景象呢?想象一边享受着安卓的便捷,...
投影仪装安卓系统,开启智能投影... 你有没有想过,家里的老式投影仪也能焕发第二春呢?没错,就是那个曾经陪你熬夜看电影的“老伙计”,现在它...
安卓系统无线车载carplay... 你有没有想过,开车的时候也能享受到苹果设备的便利呢?没错,就是那个让你在日常生活中离不开的iOS系统...
谷歌安卓8系统包,系统包解析与... 你有没有发现,手机更新换代的速度简直就像坐上了火箭呢?这不,最近谷歌又发布了安卓8系统包,听说这个新...
微软平板下软件安卓系统,开启全... 你有没有想过,在微软平板上也能畅享安卓系统的乐趣呢?没错,这就是今天我要跟你分享的神奇故事。想象你手...
coloros是基于安卓系统吗... 你有没有想过,手机里的那个色彩斑斓的界面,背后其实有着一个有趣的故事呢?没错,我要说的就是Color...
安卓神盾系统应用市场,一站式智... 你有没有发现,手机里的安卓神盾系统应用市场最近可是火得一塌糊涂啊!这不,我就来给你好好扒一扒,看看这...
黑莓平板安卓系统升级,解锁无限... 亲爱的读者们,你是否还记得那个曾经风靡一时的黑莓手机?那个标志性的全键盘,那个独特的黑莓体验,如今它...
安卓文件系统采用华为,探索高效... 你知道吗?最近安卓系统在文件管理上可是有了大动作呢!华为这个科技巨头,竟然悄悄地给安卓文件系统来了个...
深度系统能用安卓app,探索智... 你知道吗?现在科技的发展真是让人惊叹不已!今天,我要给你揭秘一个超级酷炫的话题——深度系统能用安卓a...
安卓系统的分区类型,深度解析存... 你有没有发现,你的安卓手机里藏着不少秘密?没错,就是那些神秘的分区类型。今天,就让我带你一探究竟,揭...
安卓系统铠无法兑换,揭秘无法兑... 最近是不是有很多小伙伴在玩安卓系统的游戏,突然发现了一个让人头疼的问题——铠无法兑换!别急,今天就来...
汽车安卓系统崩溃怎么刷,一键刷... 亲爱的车主朋友们,你是否曾遇到过汽车安卓系统崩溃的尴尬时刻?手机系统崩溃还能重启,但汽车系统崩溃了,...
miui系统可以刷安卓p系统吗... 亲爱的手机控们,你是否对MIUI系统情有独钟,同时又对安卓P系统的新鲜功能垂涎欲滴?今天,就让我带你...