简单说说对QT中moveToThread实现多线程操作的理解

2023-11-08

  在平时的编码过程中经常碰到QT的多线程问题,也大量接触了QT中的两种主流多线程写法,一种是继承QThread类并重载run函数,在run函数中写一个状态机或者计时器来实现对线程运作;一种是通过moveToThread的方式实现事件托管从而实现线程运作。前者虽然是传统写法但是弊病较多,这里主要针对后者来进行说明与理解。
  1.常见情况分析:该方法在进行代码编写时的常见情况如下:

class tempActive
{
public:
	tempActive()
    {
    	...
    	a = new A;
    	m_thread = new QThread;
    	a->moveToThread(m_thread);
    	...
    ]
private:
	A* a;
	QThread* m_thread;
    ...
};

  上述代码中,tempActive为某一工作相关类,A为某一自定义类或预定义类,其实例a与实例m_thread往往在tempActive的构造函数中实现,并在其中将a实例moveToThread至m_thread线程之中。这里需要着重理解一点,并非是将a实例相关的所有的工作“移动”到了m_thread线程,而是将所有a实例相关的事件托管到m_thread线程执行。换句话说,就是通过信号槽connect或者invokeMethod触发a实例中槽函数产生的事件,将会被放置到m_thread线程中执行,从而实现了多线程工作。也就是说,此时通过a->show()等方式调用直接调用a实例中的函数,无法实现多线程功能。
  2.实验验证:为了验证以及加强理解上述结论,在这里做一个简单的实验如下:

class A : public QObject
{
    Q_OBJECT
public:

public slots:
    void show()
    {
        qDebug() << "show:" << QThread::currentThreadId();
    }
};

class MainWindow : public QObject
{
    Q_OBJECT

public:
    explicit MainWindow(QObject *parent = 0);
    ~MainWindow();
public slots:
    void mainShow() {qDebug() << "mainShow:" << QThread::currentThreadId();}
signals:
    void s_test();
private:
    A* a;
    QTimer* m_timer;
    QThread* m_thread;
};

MainWindow::MainWindow(QObject *parent) :
    QObject(parent)
{
    a = new A;
    m_thread = new QThread;
    m_timer = new QTimer;
    m_timer->setInterval(500);
    m_thread->start();

    qDebug() << "A before move:" << QThread::currentThreadId();	//A before move: 0x2a0c
    a->show();	//show: 0x2a0c
    QMetaObject::invokeMethod(a,"show",Qt::DirectConnection);	//show: 0x2a0c
    QObject::connect(this,SIGNAL(s_test()),a,SLOT(show()),Qt::DirectConnection);
    emit s_test();	//show: 0x2a0c
    QObject::disconnect(this,SIGNAL(s_test()),a,SLOT(show()));

    a->moveToThread(m_thread);
    qDebug() << "A after move:" << QThread::currentThreadId();	//A after move: 0x2a0c
    a->show();	//show: 0x2a0c
    QMetaObject::invokeMethod(a,"show",Qt::BlockingQueuedConnection);	//show: 0x3a9c
    QObject::connect(this,SIGNAL(s_test()),a,SLOT(show()),Qt::BlockingQueuedConnection);
    emit s_test();	//show: 0x3a9c
    QObject::disconnect(this,SIGNAL(s_test()),a,SLOT(show()));

    qDebug() << "m_timer before move:" << QThread::currentThreadId();	//m_timer before move: 0x2a0c
    m_timer->moveToThread(m_thread);
    this->moveToThread(m_thread);
    qDebug() << "m_timer after move:" << QThread::currentThreadId();	//m_timer after move: 0x2a0c
    QObject::connect(m_timer,SIGNAL(timeout()),this,SLOT(mainShow()),Qt::DirectConnection);	
    QMetaObject::invokeMethod(m_timer,"start",Qt::BlockingQueuedConnection);	//mainShow: 0x3a9c
}

  在上述函数中,通过MainWindow的构造函数进行实验,这里分步分析下:

  • 当实例a还未移动至m_thread之前,其所有的相关操作均处于当其被new时所处的线程,由于MainWindow在主线程中被构造,所以此时实例a位于主线程0x2a0c。此时通过任何方式,无论直接调用a_>show(),抑或是通过信号槽和invokeMethod调用show(),最终触发时show()必然在主线程0x2a0c之中。
  • 当实例a被移动至m_thread之后,其相关事件被托管,但是该实例本身仍位于主线程0x2a0c中,但是通过信号槽和invokeMethod调用show()时发生在m_thread线程0x3a9c之中。
  • 当m_timer与this被移动至m_thread之后,其所处线程仍不变为主线程0x2a0c,此时m_timer与this为同一线程,所以信号槽连接时使用DirectConnection,并且需要通过invokeMethod方式来调用m_timer的start方可在主线程0x2a0c中调用m_thread中的m_timer.start()函数(不然会报QTimer无法在另外线程打开的错误,这其实是QT对于QTimer机制的一种保护,有兴趣的读者可以研究下这里将QTimer进行moveToThread之后对于线程的限制保护机制),最后执行的mainShow()函数也确确实实的都在m_thread的线程0x3a9c中执行。

  3.结论总结

  • moveToThread方式并非“无脑”移动,是一种事件的托管;
  • 事件的产生只能通过信号槽或invokeMethod方式来实现,其他的方式(如直接调用)将会导致所调用函数在进行直接调用的线程之中执行,而非moveToThread之后的线程。
  • 由于QTimer操作对于线程的限制性,需要保证执行QTimer的相关函数时,如果想采用直接调用则需保证调用函数线程与QTimer所处线程一致,否则就必须使用信号槽或invokeMethod的方式来调用QTimer相关的函数。
  • “QT官方文档moveToThread的Warning”:moveToThread往往只能将当前对象从其当前所处线程“推”到某一线程中去(比如1中的常见情况,即在构造函数中将实例a从构建tempActive的线程“推”到了m_thread线程中),不能将当前对象从某线程中“拉”到该线程(即无法在实例a不处在的线程中执行对实例a的moveToThread操作,因为无法在另一线程控制a的自身线程)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单说说对QT中moveToThread实现多线程操作的理解 的相关文章

  • 什么时候使用Q_NULLPTR?

    I see Q NULLPTR在 Qt 源代码和示例中被广泛使用 但我没有找到关于它到底是什么以及何时应该使用的文档 例如在这个官方示范 http doc snapshots qt io qt5 5 6 qtserialbus can ma
  • 没有什么可以帮助解决 Qt 中的“对 vtable 的未定义引用”

    我无法构建此错误 未定义对 CustomUndoStack 的 vtable 的引用 这是代码 class CustomUndoStack public QObject Q OBJECT public int main int argc c
  • Qt - 如何将数据与 QTableWidgetItem 关联?

    我想将附加数据与插入表中的每个 QTableWidgetItem 相关联 以便将来在单击表项时使用该数据 但这些数据不应该是可见的 我怎样才能做到这一点 您可以使用QTableWidgetItem setData http doc qt i
  • Qt 不支持 Visual Studio 的 Unicode 或字体错误

    我是初学者 现在我正在学习 Qt 并使用 Visual Studio 扩展 Qt VS Tool 2 4 3 我使用的文本是越南语 当我构建程序时 它很好 但按钮显示特殊字符 我已经阅读了一些有关字体错误的主题 但它与此错误无关 我的代码
  • OpenCV(C++/Qt)-cornerSubPix 错误

    Hello 我在使用 imgproc hpp 文件中的cornerSubPix 方法时遇到问题 我不明白缺少哪个库或者有什么错误 我在 OS X 10 10 3 上使用 Qt 5 4 1 并使用 OpenCV 3 0 0 C 库 这是我的代
  • 设置 ItemIsMovable 标志时,子项在 QGraphicsView 中不可移动

    要调整项目中的项目QGraphicsView http qt project org doc qt 5 0 qtwidgets qgraphicsview html 我将表示顶点的子项放到要移动的项上 使用构造函数中建立的父子关系 就是下图
  • 当鼠标位于 Qt 窗口的自定义小部件上时,如何移动整个窗口?

    假设我有一个自定义小部件并将其添加到 qt 的主窗口中 如您所见 红色区域是自定义小部件 我想要做的是 当鼠标在红色区域按下并移动时 整个窗口也会移动 我知道如何简单地实施mousePressEvent and mouseMoveEvent
  • 在Linux上运行MFC程序

    我有一个相当大的基于 MFC 的程序 我的任务是让它在 Linux 上运行 我已经解释过 这需要将程序重新编写为带有 STL 的直接 C 更多工作 或者重新编写为 Qt C 更少工作 现在我被告知 我需要编写包装器以使每个 MFC 类在 L
  • 如何在使用 QSS 悬停父 QFrame 时设置子 QLabels 的颜色?

    我试图使用样式表设置 QFrame 内 2 个标签的悬停状态颜色 但无论是否存在实际悬停 框架都会采用悬停状态 See screenshot 我有一个带有 QLabels 的 QFrame 我将默认颜色设置为绿色和紫色 当我将鼠标悬停在 Q
  • 如何使用 PyQt5 在 QWidget 上设置 numpy 数组图像

    我正在将相机中的图像作为 numpy 数组读取 我的目标是将其放入 pyqt5 的 Qwidget 中并在我的 mainwindow gui 程序上打印 但我收到以下错误 TypeError QPixmap argument 1 has u
  • 如何在 Qt 5.3 中将 QByteArray 转换为字符串?

    我正在使用一些函数来转换QVector s to QByteArray s 例如 QByteArray Serialize serialize QVector
  • 故障转储分析:CxxUnhandledExceptionFilter

    我有一个崩溃小型转储需要分析 我的程序是多线程Qt5应用程序 我不是调试专家 但通常我可以轻松找到程序失败的地方 但这次我不能 我在 Visual Studio 2010 中打开转储文件 单击 仅使用本机调试 它向我显示问题所在 它是位置为
  • 如何在“单击”槽中使用 QApplication::mouseButtons() 来判断鼠标按钮?

    我有一个 QMainWindow 并且想要处理来自其中较小的小部件 例如 tableview 的 单击 信号 最初我将信号连接到这个 QMainWindow 的插槽 这是最常见的方法 现在我需要判断单击了哪个鼠标按钮 并对左右按钮执行不同的
  • Qt、QML 和 Windows 8 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我一直对Qt框架引入的QML很好奇 但从未有机会使用它 但现在随着 Windows 8 的到来 基于旧式小部件的界面将变得过时 只是我
  • 如何完全删除 QLayout 的边距(特定于 Mac OS)

    Let me explain a simplified situation In Qt Creator create a QHBoxLayout containing a QPushButton and another QHBoxLayou
  • Qt 中浮点数的强制点而不是逗号

    我有一个非常基本的问题 如何在 Qt 中强制使用浮点数中的点而不是逗号 我的操作系统有法语版本 其他问题 是否可以显示带有千位分隔符空格的数字 尝试这个 QLocale loc QLocale system current locale l
  • 更改 QT 主窗口的标题字体

    我想知道如何更改 QT 主窗口的标题字体 请参阅随附的屏幕截图 我尝试更改样式表等 但它不起作用 我也尝试使用 C 发送消息 但这也有效 SendMessage form gt effectiveWinId WM SETFONT WPARA
  • pyqt在mac osx雪豹中安装问题

    我正在学习制作桌面应用程序的教程 使用python和qt4 我下载并安装了qt Creator ide 创建了 ui文件 然后我必须使用pyuic4对其进行转换 我已经尝试了很多东西但仍然无法做到 我以为pyuic4会用Qt Creator
  • 我可以取消选中组框中的一组 RadioBottom 吗?

    组 Box 内的单选底部将被视为一组底部 它们是互斥的 我怎样才能清理他们的检查状态 我有几件收音机底部 其中一件经过检查 我怎样才能 清洁 取消选中 所有收音机底部 setChecked 在组内不起作用 我尝试做以下事情但失败了 我的代码
  • 更改 Qt 中的标签

    我正在尝试制作一个由按钮和标签组成的简单程序 当按下按钮时 它应该将标签文本更改为程序内 QString 变量中的任何内容 到目前为止 这是我的代码 这是我的 widget h 文件 class Widget public QWidget

随机推荐

  • python比较两个csv文件,并打印出不同的行号,列号,数据

    https blog csdn net The Handsome Sir article details 121251433 def compareFile file1 file2 如果相等返回 1 0 0 如果不相等返回 0 a b a
  • 【满分】【华为OD机试真题2023 JS】AI处理器组合

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 AI处理器组合 知识点数组 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 某公司研发了一款高性能AI处理器 每台物理设备具备8颗AI处理器 编号分别为0 1 2
  • Y形电路与三角电路转换,网孔和节点分析法

    Y形电路与三角电路转换 网孔和节点分析法 Y形电路与三角电路转换 推导过程与之前的电压源和电流源的转换类似 用系数相等即可等价转换 此处直接给出结论与记法 网孔分析法 自电阻 在这个网孔中所有电阻的和 互电阻 网孔1与网孔2之间的电阻 将每
  • 机器学习——决策树算法

    一 实验目的 掌握如何实现决策树算法 用并决策树算法完成预测 二 实验内容 本次实验任务我们使用贷款申请样本数据表 该数据表中每列数据分别代表ID 年龄 高薪 有房 信贷情况 类别 我们根据如下数据生成决策树 使用代码来实现该决策树算法 三
  • Linux->线程库接口

    目录 前言 1 进程和线程 2 线程库接口 2 1 线程库基础理解 2 2 创建线程 2 2 线程资源回收 2 3 线程分离 前言 本篇主要是对Linux原装线程库的函数接口进行学习 还有一部分的线程概念补充 1 进程和线程 博主在上一篇文
  • android--emo的来源

    文章目录 前言 第一次安装 bug出现了 idea配置android开发环境 碰运气 重新下载 导入项目 测试成功 感悟 前言 记录一下我安装android studio的心路历程 为什么就我遇到这么多问题 第一次安装 这学期新开的移动应用
  • python选择与循环结构之判断三角形:任意输入三个整数作为三角形边长,判断三条边能否构成三角形,并判断是等边三角形、等腰三角形,直角三角形,还是一般三角形。

    问题描述 任意输入三个整数作为三角形边长 判断三条边能否构成三角形 并判断是等边三角形 等腰三角形 直角三角形 还是一般三角形 实现代码如下 a int input 请输入a b int input 请输入b c int input 请输入
  • Winsock Error Codes

    Winsock Error Codes 10004 WSAEINTRInterrupted function call This error indicates that a blocking call was interrupted by
  • JavaScript 严格模式(use strict)

    JavaScript严格模式 又称为 use strict 模式 是JavaScript语言的一种更严格的运行模式 严格模式规定了一些限制 用于防止程序员犯一些常见的错误 以保证代码的正确性和安全性 在JavaScript严格模式中 不允许
  • 刷脸支付智慧经营创业红利赢在坚持不懈

    这是一个最好的时代 我们身处繁华的都市 有着一个体面稳定的工作 科技日新月异 生活便捷高效 这是一个最坏的时代 房价水涨船高 工资涨幅完全跟不上物价的涨幅 8090后年轻人们面临着巨大的生活压力 钱 成为了禁锢他们的牢笼 在这个时代 普通人
  • Mybatis如何处理Result Maps collection already contains value for xxx异常呢?

    转自 Mybatis如何处理Result Maps collection already contains value for xxx异常呢 下文笔者讲述一次mybatis异常的处理分享 如下所示 Mybatis异常摘要 2022 08 1
  • Java初识RabbitMQ一交换机(fanout exchange)

    扇型交换机 funout exchange 将消息路由给绑定到它身上的所有队列 而不理会绑定的路由键 如果 N 个队列绑定到某个扇型交换机上 当有消息发送给此扇型交换机时 交换机会将消息的拷贝分别发送给这所有的 N 个队列 因为扇型交换机投
  • 取消已设置为SVN的文件夹(清理SVN标志)

    取消CheckOut后的文件与svn的联系 Windows Registry Editor Version 5 00 HKEY LOCAL MACHINE SOFTWARE Classes Folder shell DeleteSVN 删除
  • 代码随想录训练营第14天

    参考 代码随想录 一 理论基础 一 二叉树的种类 满二叉树 完全二叉树 二叉搜索树 平衡二叉搜索树 二 二叉树的存储方式 顺序存储 顺序存储的元素在内存中是连续分布的 通常用数组来存储 如果父节点的数组下标是 i 那么它的左孩子就是 i 2
  • ucos学习资料、论坛等

    论坛 http bbs elecfans com forum php mod forumdisplay fid 301 typeid 505 教程推荐 第一步 嵌入式实时操作系统 COS II原理及应用 任哲编著 首选任哲的这本书 我建议先
  • 对IOC和DI的通俗理解

    学习过spring框架的人一定都会听过Spring的IoC 控制反转 DI 依赖注入 这两个概念 对于初学Spring的人来说 总觉得IoC DI这两个概念是模糊不清的 是很难理解的 今天和大家分享网上的一些技术大牛们对Spring框架的I
  • Flink ML API,为实时机器学习设计的算法接口与迭代引擎

    摘要 本文整理自阿里巴巴高级技术专家林东 阿里巴巴技术专家高赟 云骞 在 Flink Forward Asia 2021 核心技术专场的演讲 主要内容包括 面向实时机器学习的 API 流批一体的迭代引擎 Flink ML 生态建设 一 面向
  • Linux下快速查看CPU使用情况的相关命令

    Linux下快速查看CPU使用情况比较常用的命令是free top ps 这篇文章来看下如何在Linux下检查服务器的CPU使用情况 我的Linux是Linux Ubuntu server 15 04 如果是图形界面 有些统计会看起来更直观
  • Intellij Idea创建一个简单的java项目

    2016年11月12日 我即将要离开象牙塔 校园 踏入社会 想想未来我是某个公司的一个程序员 再对比一下小时的梦想 好像出入挺大的 今天我不得不为即将的工作准备 一个java开发工程师 但是我现在是一个小小的菜鸟 所以要学习 好了 不说这些
  • 简单说说对QT中moveToThread实现多线程操作的理解

    在平时的编码过程中经常碰到QT的多线程问题 也大量接触了QT中的两种主流多线程写法 一种是继承QThread类并重载run函数 在run函数中写一个状态机或者计时器来实现对线程运作 一种是通过moveToThread的方式实现事件托管从而实