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()本身是线程安全的。

相关内容

热门资讯

安卓系统苹果手机识别,跨界融合... 你知道吗?在科技飞速发展的今天,手机已经成为了我们生活中不可或缺的一部分。而说到手机,安卓系统和苹果...
harmonyos系统是不是安... 亲爱的读者,你是否曾好奇过HarmonyOS系统与安卓系统之间的关系?是不是安卓的“亲戚”?今天,就...
手机怎么装系统安卓,安卓系统安... 手机卡顿了?想给安卓系统来个大变身?别急,跟着我一步步来,保证让你的手机焕然一新!一、准备工作在开始...
安卓Linux系统内网穿透,A... 你有没有想过,你的安卓手机里那些看似普通的APP,其实可能正在悄悄地帮你打通网络世界的任督二脉呢?没...
win怎么安装安卓系统,Win... 亲爱的读者,你是不是对Win系统上的安卓应用垂涎已久,但又苦于不知道如何安装安卓系统呢?别急,今天我...
升级小米平板安卓系统,畅享全新... 你有没有发现,你的小米平板用久了,是不是感觉有点卡呢?别急,今天就来教你怎么给它来个系统升级,让它焕...
捷豹安卓系统车载,捷豹安卓系统... 哇,你有没有想过,当你的手机和汽车融为一体,会是怎样的体验呢?想象你正驾驶着你的捷豹,车窗外的风景如...
安卓1到10系统,安卓1.0至... 你有没有想过,手机里的安卓系统就像是我们生活中的好朋友,从青涩的少年成长为稳重的青年呢?从安卓1.0...
安卓8.0停用系统应用,提升使... 你知道吗?最近安卓系统又来了一次大动作,那就是安卓8.0系统开始停用一些系统应用了。这可真是让人有点...
安卓系统修改mtu值,轻松提升... 你有没有想过,你的安卓手机其实是个小小的电脑呢?它里面藏着许多可以自定义的秘密功能,就像修改MTU值...
安卓平板改window系统,探... 你有没有想过,你的安卓平板其实可以摇身一变,变成一个Windows系统的电脑呢?没错,就是那种可以运...
时空猎人安卓苹果系统,探索无尽... 你知道吗?最近在手机游戏圈里,有一款叫做《时空猎人》的游戏可是火得一塌糊涂呢!不管是安卓用户还是苹果...
安卓9.0系统的电视,新一代电... 亲爱的读者们,你是否也像我一样,对科技新玩意儿充满好奇?今天,我要和你聊聊一个让人眼前一亮的话题——...
小pc安装安卓系统,轻松安装安... 你有没有想过,你的小PC也能变身成为安卓系统的超级玩家呢?没错,就是那个平时默默无闻的小家伙,现在也...
高通备份安卓系统,全方位数据安... 你知道吗?在这个科技飞速发展的时代,手机备份可是个不得不提的话题。尤其是对于安卓用户来说,选择一个靠...
谷歌安卓系统有多少,从诞生到全... 你有没有想过,那个无处不在的谷歌安卓系统,究竟在全球有多少用户呢?它就像一个神秘的数字,每天都在悄悄...
fc黄金传说安卓系统,畅享复古... 你有没有听说最近安卓系统上的一款超酷的游戏——《FC黄金传说》?这款游戏可是让不少玩家都沉迷其中,今...
变小的我安卓系统,安卓系统演变... 你有没有发现,最近你的手机好像变轻了?没错,说的就是你,那个陪伴你多年的安卓系统。它悄无声息地进行了...
vivo安卓系统小彩蛋,体验科... 你知道吗?在vivo的安卓系统中,竟然隐藏着一些超有趣的小彩蛋!这些小彩蛋就像是在手机里埋下的宝藏,...
安卓系统如何强制重启,安卓系统... 手机突然卡壳了,是不是又该给它来个“大保健”了?没错,今天就来聊聊安卓系统如何强制重启。别小看这个看...