QObject_thread

2024-01-12 02:12
文章标签 thread qobject

本文主要是介绍QObject_thread,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

QObject::thread

QThread *QObject::thread()

返回对象所在的线程。

QThread *QObject::thread() const
{return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
}

void QObject::moveToThread(QThread *targetThread)

将此对象及其孩子关联到targetThread线程,事件处理将在targetThread中继续进行,
在线程关联被改变之前QEvent::ThreadChange事件被发送给这个对象和其孩子对象。

注意:

  1. widget类型(继承QWidget的类)对象只能在主线程中,所以调用moveToThread无效。
  2. 如果对象有父对象,则不能移动该对象。
  3. 调用者必须与此对象在同一线程,除非此对象没有关联线程
  4. 该对象的计时器timer首先在当前线程中停止,然后在targetThread中重新启动(间隔相同)。因此,在线程之间不断移动对象会无限期地延迟计时器事件。
  5. 如果targetThread为nullptr,则此对象及其子对象的所有事件处理都将停止,因为它们不再与任何线程相关联。
使用样例:
int main()
{QThread *th = new QThread();myobject *obj1= new  myobject("boj1");obj1->connect(obj1,&myobject::signal1,obj1,&myobject::slot1);obj1->moveToThread(th);//调用在主线程与obj1同一线程//因为线程启动后才会执行事件循环,所以必须启动线程th->start();qDebug()<<"main QThreadid = "<<QThread::currentThreadId()<<",date="<<QDateTime::currentSecsSinceEpoch();emit obj1->signal1(111);return 0;
}
函数解读:
void QObject::moveToThread(QThread *targetThread)
{Q_D(QObject);//如果对象有父对象,则不能移动该对象。if (d->parent != nullptr) {qWarning("QObject::moveToThread: Cannot move objects with a parent");return;}//对象是widget类型的不能移动widget类型的只能在主线程中//继承QWidget的类都是widget类型//explicit QWidget(QWidget* parent = nullptr, Qt::WindowFlags);if (d->isWidget) {qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");return;}//调用此函数的所在线程,即当前线程QThreadData *currentData = QThreadData::current();//移动到的目标线程QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;//对象所在线程数据,QThreadData *thisThreadData = d->threadData.loadRelaxed();//如果对象没有关联线程,并且目标线程等于当前线程,可以移动if (!thisThreadData->thread.loadAcquire() && currentData == targetData){//我们允许将没有线程关联的对象移动到当前线程currentData = d->threadData;} else if (thisThreadData != currentData) {//只能在object所在的线程里面调用此函数qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n""Cannot move to target thread (%p)\n",currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);return;}// 移动前先发送QEvent::ThreadChange事件d->moveToThread_helper();if (!targetData)targetData = new QThreadData(0);//确保在我们移动这个对象时没有人添加/删除连接QMutexLocker l(signalSlotLock(this));QOrderedMutexLocker locker(&currentData->postEventList.mutex,&targetData->postEventList.mutex);// 保持currentData存活(因为我们已经锁定了它)currentData->ref();// 真正的移动对象d_func()->setThreadData_helper(currentData, targetData);locker.unlock();// now currentData can commit suicide if it wants tocurrentData->deref();
}void QObjectPrivate::moveToThread_helper()
{Q_Q(QObject);QEvent e(QEvent::ThreadChange);//sendEvent发送ThreadChange事件//因为sendEvent是同步调用,所以等对象处理完事件后,才能继续往下走QCoreApplication::sendEvent(q, &e);//给对象的所有孩子发送ThreadChange事件for (int i = 0; i < children.size(); ++i) {QObject *child = children.at(i);child->d_func()->moveToThread_helper();}
}void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData)
{for (int i = 0; i < currentData->postEventList.size(); ++i) {const QPostEvent &pe = currentData->postEventList.at(i);if (!pe.event)continue;if (pe.receiver == q) {//将此post事件移动到targetList中targetData->postEventList.addEvent(pe);const_cast<QPostEvent &>(pe).event = nullptr;++eventsMoved;}}//当前线程在调用moveToThread()后不应该恢复currentSenderConnectionData *cd = connections.loadRelaxed();if (cd) {if (cd->currentSender) {cd->currentSender->receiverDeleted();cd->currentSender = nullptr;}// 调整连接中的receiverThreadId值if (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;}}}// 设置新线程数据targetData->ref();threadData.loadRelaxed()->deref();//同步其孩子到targetData线程//QObject的孩子肯定不是widget一类,所以可以直接移动不用判断for (int i = 0; i < children.size(); ++i) {QObject *child = children.at(i);child->d_func()->setThreadData_helper(currentData, targetData);}
}

这篇关于QObject_thread的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/596481

相关文章

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html  Thread Index和Thread ID之间有什么关系呢?(线程架构参考这里:CUDA C++ Programming Guide (nvidia.com)open in new window) 1维的Thread Index,其Thread

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本  1.2 认识Nano版本 2 STM32F446U上移植RT-Thread  2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet  2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码  2.2.3.

GTK中创建线程函数g_thread_new和g_thread_create的区别

使用GThread函数,需要引用glib.h头文件。 这两个接口的核心区别就是  g_thread_create 是旧的接口,现在已经不使用了,而g_thread_new是新的接口,建议使用。 g_thread_create: g_thread_create has been deprecated since version 2.32 and should not be used in n

基于 rt-thread的I2C操作EEPROM(AT24C02)

一、AT24C02 The AT24C01A/02/04/08A/16A provides 1024/2048/4096/8192/16384 bits of serial electrically erasable and programmable read-only memory (EEPROM) organized as 128/256/512/1024/2048 words of 8 b

[项目][CMP][Thread Cache]详细讲解

目录 1.设计&结构2.申请内存3.释放内存4.框架 1.设计&结构 Thread Cache是哈希桶结构,每个桶是一个按桶位置映射大小的内存块对象的自由链表 每个线程都会有一个Thread Cache对象,这样每个线程在这里获取对象和释放对象时是无锁的 TLS – Thread Local Strorage Linux gcc下TLSWindows vs下TLS

线程池工具类——Thread学习笔记

记录一下线程池工具类: /*** 线程池工具类* @author lixiang* @date 2018年10月10日 - 11:10* @history 2018年10月10日 - 11:10 lixiang create.*/public class ThreadPoolHelper {private static final Logger logger = LoggerFactory.g

模拟线程死锁——Thread学习笔记

记录一下之前写过的一段模拟死锁的代码: /*** 模拟死锁** @author lixiang* @date 2018年10月12日 - 9:51* @history 2018年10月12日 - 9:51 lixiang create.*/public class HoldLockDemo {private static Object[] lock = new Object[10];priv

C++11 Thread线程池、死锁、并发

一、线程与进程         进程:运行中的程序         线程:进程中的小进程 二、线程库的使用         包含头文件#include<thread> 2.1 thread函数         具体代码: void show(string str) {cout << "This is my word : " << str << endl;}int main() {t

Exception in thread main java.lang.NoClassDefFoundError: org/apache/juli/l

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/juli/l MyEclipse整合免安装版的Tomcat7,------> 看图吧 最后这个就可以在myeclipse里,使用你的tomcat,而不是用.bat打开!!!!

实现多线程有两种方法: Thread类继承和Runnable接口实现

l 创建线程的第一种方式:继承Thread类。 步骤: 1,定义类继承Thread。 2,复写Thread类中的run方法。 目的:将自定义代码存储在run方法。让线程运行。//run();仅仅是对象调用方法。而线程创建了,并没有运行。 3,调用线程的start方法, 该方法两个作用:启动线程,调用run方法。 Demo d = new Demo();//创建好一个线程