QT moveToThread解析
目录
- 简介
- 源码分析
- 判断是否可以执行移动动作
- 执行移动动作
- 调用moveToThread_helper
- 调用setThreadData_helper
简介
每一个QObject子类都会关联到一个具体QThread线程上,QObject有一个QThreadObject数据成员,该成员在Qobject构造时关联到具体的线程上:
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{...QThreadData *threadData; // id of the thread that owns the object...
}QObject::QObject(QObjectPrivate &dd, QObject *parent): d_ptr(&dd)
{...d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();d->threadData->ref();...
}
可以看到,其实对象在构造时,就会与具体的线程关联起来:
1)如果有parent且parent已经关联到具体线程,则会直接关联到parent所在的线程;
2)否则,关联到当前线程。
而moveToThread用于将一个QObject子类对象移到另一个线程,常见于多线程编程中。
源码分析
movetoThread主要分两部分:
- 判断是否可以执行移动动作
1.1 已经位于目标线程不用移动
1.2 有parent的对象不能移动
1.3 UI控件不能移动 - 执行移动动作
2.1 发送threadChange事件
2.2 处理消息队列中消息receiver为自己的消息
2.3 处理自己的connection
2.4 修改threadData
判断是否可以执行移动动作
- 已经位于目标线程不用移动
if (d->threadData->thread.loadAcquire() == targetThread) {// object is already in this threadreturn; }
threadData的thread其实是指向一个QThread对象;
class QThreadData {...QAtomicPointer<QThread> thread;... }
如果自己已经在目标线程了,那当然啥都不用做了。
- 有parent的对象不能移动
if (d->parent != 0) {qWarning("QObject::moveToThread: Cannot move objects with a parent");return; }
这个就是这样写的,我暂时不知道为啥,也许是因为处理起来很麻烦。
- UI控件不能移动
if (d->isWidget) {qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");return; }
我们知道QT是不能在非UI线程创建控件的,所以这个也很好理解,不能将控件移到非UI线程。
三个判断到这里就结束了。下面看看具体的移动动作涉及的几个方面:
执行移动动作
调用moveToThread_helper
- 发送threadChange事件
前面判断完后,会调用// prepare to move d->moveToThread_helper();
moveToThread_helper很简单,就是发送个事件,然后对子对象递归调用。
void QObjectPrivate::moveToThread_helper() {Q_Q(QObject);QEvent e(QEvent::ThreadChange);QCoreApplication::sendEvent(q, &e);for (int i = 0; i < children.size(); ++i) {QObject *child = children.at(i);child->d_func()->moveToThread_helper();} }
发送了ThreadChange事件给自己。
QObject中对此事件的处理就是释放定时器:case QEvent::ThreadChange: {Q_D(QObject);QThreadData *threadData = d->threadData;QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();if (eventDispatcher) {QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);if (!timers.isEmpty()) {// do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).eventDispatcher->unregisterTimers(this);QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection,Q_ARG(void*, (new QList<QAbstractEventDispatcher::TimerInfo>(timers))));}}break; }
由于处理的是该对象已注册的定时器,所以在这一步用到的threadData得是转移前的线程,所以首先就是发这个消息。
调用setThreadData_helper
- 处理消息队列中消息receiver为自己的消息
调用moveToThread_helper完后,之后的几个步骤都是setThreadData_helper调用里的:if (!targetData)targetData = new QThreadData(0);currentData->ref();// move the objectd_func()->setThreadData_helper(currentData, targetData);
int eventsMoved = 0; for (int i = 0; i < currentData->postEventList.size(); ++i) {const QPostEvent &pe = currentData->postEventList.at(i);if (!pe.event)continue;if (pe.receiver == q) {// move this post event to the targetListtargetData->postEventList.addEvent(pe);const_cast<QPostEvent &>(pe).event = 0;++eventsMoved;} } if (eventsMoved > 0 && targetData->hasEventDispatcher()) {targetData->canWait = false;targetData->eventDispatcher.loadRelaxed()->wakeUp(); }
这个可以分成2小步:
1)遍历对象所处当前线程中所有事件,将receiver为自己的事件全部移到(不是复制)新线程的消息队列里。
2)如果真的有事件被移动,则尝试对目标线程调用wakeUp,告诉线程可以起来工作了。 - 处理自己的connection
ConnectionData *cd = connections.loadRelaxed(); if (cd) {if (cd->currentSender) {cd->currentSender->receiverDeleted();cd->currentSender = nullptr;}// adjust the receiverThreadId values in the Connectionsif (cd) {auto *c = cd->senders;while (c) {QObject *r = c->receiver.loadRelaxed();if (r) {Q_ASSERT(r == q);targetData->ref();QThreadData *old = c->receiverThreadData.loadRelaxed();if (old)old->deref();c->receiverThreadData.storeRelaxed(targetData);}c = c->next;}}}
这块儿代码比较长,暂时还没想明白,后面想明白了再来更新,有大佬知道的话也可以说下。
- 修改threadData
targetData->ref(); threadData->deref(); threadData = targetData;
全部事情都做完后,用到threadData的地方都处理完了,就可以更新threadData了,
ref
增加引用,deref
解引用。
上面执行完后,同moveToThread_helper一样,也会遍历子对象递归调用setThreadData_helper。
QT moveToThread解析相关推荐
- 一个基于QT的解析interproscan结果的C++成员函数
结构域预测软件interproscan提供多种输出格式,出于后期分析的需要,选用了gff3格式.我比较喜欢结合数据库进行分析,所以先要把数据导入数据库. 我之前用QT写好了界面,所以只要在菜单里添加一 ...
- Qt:解析xml文件
XML 什么事XML文件 XML,可扩展标记语言(Extensible Markup Language),是一种标记语言.一般用 于数据存储.配置文件存储,(Qt的ui文件就是xml)也可以跨平台跨语 ...
- QT——JSON解析
一些相关知识的链接: 有关JOSN相关的基础知识:JSON基础 有关QT中JSON的操作:QT中JSON的操作 一个在线工具,可以进行JSON格式化分析的网址:JSON格式化 如何从网络中轻松得到JS ...
- QT Json解析方法
QT 与WEB的交互,大部分就是客户端与网页的交互,有时,我们需要得到服务器返回的具体的数据,就通过客户端与网页交互的过程中拿到所需要的参数,在我的另一篇博文中有讲到过http://blog.csdn ...
- qt中解析json字符串的时候出现错误missingNameSeperator
概述 当解析json字符串,编译代码的时候没有问题,但是当程序调式运行到解析json字符串的时候,即这句: QJsonParseError parseError;QJsonDocument doc = ...
- Qt JSON解析生成笔记
对于这样一段json {"name": "布衣食","gender": "Male","age": ...
- QT无法解析的外部符号问题
moc_widget.obj:-1: error: LNK2019: 无法解析的外部符号 "private: void __thiscall Widget::on_pushButton_6_ ...
- QT moveToThread线程理解
一.moveToThread创建开启线程步骤: (1)创建继承自QObject类,实现槽函数. (2)将QObject类通过moveToThread方法移到QThread线程中,使QObject类依附 ...
- qt moveToThread错误分析
概念:movetothread的意思就是把某个东西移动到线程里,然后通过信号与槽的方式实现调用.但是使用movetothread时,必须是继承QObject类的类. 错误情况:在使用movetothr ...
最新文章
- 使用CNN做文本分类——将图像2维卷积换成1维
- 相机模拟激光雷达 建图
- excel转kml工具_CAD+Excel还能这样玩?你用对了嘛!
- 机器学习如何计算特征的重要性_机器学习之特征缩放
- php进销存 手机版_酒水批发用传统本地化部署进销存与云进销存手机版的区别!...
- cookie 的使用
- SqlConnection的open打开后没关闭的后果
- android 代码设置alignleft,如何动态的设置Relative Layout中按钮的layout_align_parent_right属性...
- python web flask开发框架_零基础入门python web框架Flask开发
- DCMTK:类DcmUniqueIdentifier的测试程序
- layui的checkbox示例
- 《信息安全系统设计基础》 实验五
- HTTP协议学习随笔
- Tips--Altium Designer 安装时出现Account log in
- nodejs 读取excel文件,并去重
- Python-OpenCV基本操作
- 工作缺点和不足及措施_个人工作存在的不足和改进措施_个人工作存在问题和整改方案...
- Office Tool Plus 下载使用 365 2021/2019等版本
- 计算机跳转到用户选择,win7系统开机要选择用户才能进入系统怎么办
- 安卓修改电池容量教程_安卓手机用re管理器修改电池信息增加待机时间
热门文章
- 千锋网络安全1-3days
- 阿里云企业邮箱购买流程
- 关于无状态服务(stateless service) 有状态服务(stateful service),指一篇文章就搞明白
- ssh: connect to host xxx.xxx.xxx.xxx port 22: Connection refused
- TextView逐渐加载效果
- 几大ERP软件实施方法与过程 (转)
- CSUST - 2021 组队选拔赛
- 计算机如何寻址大学计算机,寻址-天津大学计算机科学与技术学院.ppt
- 17 | 从后端到前端:微服务后,前端如何设计?
- PTA-统计大写辅音字母(详细)