qt 两种不同方式的多线程
qt多线程有2种方式
1.继承QThread的多线程
线程创建 :
QThread只有run函数是在新线程里的,但一般调用start函数后,会自动调用run函数,从而使线程起来。run()为虚函数。
如果线程已经运行,你重复调用start其实是不会进行任何处理,所以建议在start之前进行判断:使用isRunning函数。
线程退出:
在run函数调用exit()或者quit()函数可以结束线程,或在主线程调用terminate强制结束线程。
在线程运行过程调用quit、exit函数有什么效果
答案是:不会发生任何效果,QThread不会因为你调用quit或exit函数而退出正在运行到一半的run。最简单的方法是添加一个bool变量,通过主线程修改这个bool变量来进行终止,但这样有可能引起访问冲突,需要加锁。
QMutex m_lock;
QMutexLocker locker(&m_lock);
m_isCanRun = false;
常用的函数
1.void setPriority(Priority priority);
2.Priority priority() const;
3.bool isFinished() const;
4.bool isRunning() const;
5.void exit(int retcode = 0);
6.void quit(); 相当于exit(0)
7.bool wait(unsigned long time = ULONG_MAX); //线程退出过程,需要调用wait()来阻塞等待,
8.void terminate();//使用terminate之后应该使用wait
9.void start(Priority = InheritPriority);
10.virtual void run();
11.static void sleep(unsigned long);
12.void deleteLater();
Q_SIGNALS:
void started(QPrivateSignal); //开始前发射
void finished(QPrivateSignal); //结束时发射该信号
注意:
1.使用new QThread 的方式创建线程,可以使用信号finished,槽deleteLater,自动销毁分配的内存。即connect(m_printThread,&QPrintThread::finished,m_printThread,&QObject::deleteLater);2. finished和destroyed,个人认为destroyed是在finished之后发生的。所以在new QThread 的方式,线程对象虽然销毁,但指针没有置null,要使用finished信号,自定义槽函数实现线程对象置null.即connect(m_pSaveThread,&SaveDataThread::destroyed,this,&MainWindow::SaveDataThreadDestroy)
另外在线程中,也可以自定义信号,从而与主线程通信。
全局线程:
创建:
//全局线程创建时可以把窗体指针作为父对象
m_thread = new ThreadFromQThread(this);
m_thread->start();
退出:
m_thread->stopImmediately();
m_thread->wait(); //这一句是主线程等待子线程结束才能继续往下执行.(m_thread
的父类是主线程窗口,主线程窗口如果没等子线程结束就destroy的话,会顺手把m_thread
也delete
这时就会奔溃了),因此wait
的作用就是挂起,一直等到子线程结束
bool QThread::wait ( unsigned long time = ULONG_MAX ):这个函数阻塞线程直到满足下面的条件之一
1.与这个线程对象关联的线程已经结束执行(例如从run函数返回)。如果线程结束返回真值。如果线程还没有开始也返回真值
2.到达定时结束时刻。如果定时是ULONG_MAX (默认值),线程就会一直等下去(线程必须从run函数返回)。时间到,函数返回假值
局部线程:
创建:
m_printThread = new QPrintThread(NULL);//局部线程,没有父对象
m_printThread->start();
退出:
m_printThread
->stopImmediately();
connect(m_printThread,&QPrintThread::finished,m_printThread,&QObject::deleteLater);//自动销毁分配的内存
connect(m_pSaveThread,&SaveDataThread::destroyed,this,&MainWindow::SaveDataThreadDestroy); //SaveDataThreadDestroy自定义的槽函数
用一个临时变量记录当前正在运行的局部线程,由于线程结束时会销毁自己,因此要通知主线程把这个保存线程指针的临时变量设置为NULL
因此用到了QObject::destroyed
信号,在线程对象析构时通知UI把m_printThread 设置为nullptr;
void MainWindow::SaveDataThreadDestroy(QObject *obj)
{ if(qobject_cast<QObject*>(m_pSaveThread) == obj ) { m_pSaveThread = NULL; }
}
2.继承QObject的多线程
用QObject来实现多线程有个非常好的优点,就是默认就支持事件循环(Qt的许多非GUI类也需要事件循环支持,如QTimer、QTcpSocket),QThread要支持事件循环需要在QThread::run()中调用QThread::exec()来提供对消息循环的支持,否则那些需要事件循环支持的类都不能正常发送信号,因此如果要使用信号和槽,那就直接使用QObject来实现多线程。
使用QObject
来实现多线程比用继承QThread
的方法更加灵活,整个类都是在新的线程中,通过信号槽和主线程传递数据
全局线程:
m_pGetDataThread = new QThread();
m_pGetDataThreadObj = new DataThreadObject();
m_pGetDataThreadObj->moveToThread(m_pGetDataThread);
m_pGetDataThread->start();
退出
connect(m_pGetDataThread,&QThread::finished,m_pGetDataThread,&QObject::deleteLater);//看情况
connect(m_pGetDataThread,&QThread::finished,m_pGetDataThreadObj,&QObject::deleteLater);//这个函数必须使用,不然会内存泄漏
MainWindow::~MainWindow()
{ if(m_pGetDataThread) { m_pGetDataThread->quit(); }
}
//m_pGetDataThread 因为是通过new出来的,即在堆内创建,所以可以通过deleteLater让线程自杀。如果是直接实例化的,需要在析构时就需要调用QThread::wait(),而不是
connect(m_pGetDataThread,&QThread::finished,m_pGetDataThread,&QObject::deleteLater);
connect(m_pGetDataThread,&QThread::finished,m_pGetDataThreadObj,&QObject::deleteLater);//这个函数必须使用,不然会内存泄漏
m_pGetDataThread->quit();
m_pGetDataThread->wait();
//
1.善用QObject::deleteLater 和 QObject::destroyed来进行内存管理
由于多线程环境你不可预料下一步是哪个语句执行,因此,加锁和自动删除是很有用的工具,加锁是通过效率换取安全,用Qt的信号槽系统可以更有效的处理这些问题。
2.如果线程要用到消息循环,使用继承QObject的多线程方法更简单
继承QObject的多线程不能指定父对象
把所有耗时操作都作为槽函数
QMutex会带来一定的耗时,大概速度会降低1.5倍(Release模式)
3.子对象不能脱离父对象,单独切换到与父对象不同的线程中
4. QObject的子对象必须在创建其parent的线程中创建
5.在Qt中,当一个对象被移到另一个线程时,他的所有子对象也会一并转移到另外那个线程。
6.在qt中 线程创建的对象必须在线程中释放。
7.在qt中 io类不能跨线程调用Qobject。可通过信号槽的方式
线程同步问题 跟linux的思想一模一样,只是函数名不同而已。
1.QMutex
2.QMutexLocker 是对QMutex的简化,直接使用构造函数和析构函数的方式,而不是lock和unlock的调用
3. QReadWriteLock 读写锁,可以多个线程以只读方式访问,但只有一个线程以写的方式访问。
LockForRead();
LockForWrite();
unlock();
另外,QReadlocker 和QWriteLocker是QReadWriteLock的简化,如同QMutexLocker 是QMutex 的简化一样。无须使用unlock().
4. QWaitCondition
bool wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX); //解锁互斥量,并阻塞等待唤醒,唤醒后由锁定互斥量
bool wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX);
void wakeOne(); //唤醒一个等待线程,具体哪一个线程,由操作系统决定
void wakeAll();//唤醒所有等待线程
5. QSemaphore 信号量 比互斥量更高级,互斥量只能锁定一次,信号量可以多次使用,每次创建时可以设定初始值 void acquire(int n = 1); //获取n个资源
bool tryAcquire(int n = 1);
bool tryAcquire(int n, int timeout);
void release(int n = 1); //释放资源
参考:
1.https://blog.csdn.net/czyt1988/article/details/71194457
2.https://www.cnblogs.com/andreitang/archive/2011/08/25/2128508.html
qt 两种不同方式的多线程相关推荐
- Java多线程两种实现方式的对比
Java多线程两种实现方式的对比 一种,直接继承Thread类 一种,实现Thread类的Runnable接口 两种方式的区别 比如,售票厅有四个窗口,可以发售某日某次列出的100张车票,此时,100 ...
- 多线程python实现方式_python多线程的两种实现方式(代码教程)
本篇文章给大家带来的内容是关于python多线程的两种实现方式(代码教程),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 线程是轻量级的进程,进程中可划分出多个线程,线程可独立的调度 ...
- java 同步方式 lock_java的两种同步方式, Synchronized与ReentrantLock的区别
java在编写多线程程序时,为了保证线程安全,需要对数据同步,经常用到两种同步方式就是Synchronized和重入锁ReentrantLock. 相似点: 这两种同步方式有很多相似之处,它们都是加锁 ...
- 1000个苹果要分到10个箱子中去 两种分析方式
前些日子接到了一个Java开发的电话面试,接了电话人家开门见山就直接说现在是否方便,什么什么时候收到您的简历投递,是否可以进行电话面试,如果可以就可以直接开始了,emmm,这么突然,也没好意思问公司名 ...
- 【无标题】单例模式的两种创建方式:饿汉式和懒汉式
这里写自定义目录标题 单例模式的两种创建方式:饿汉式和懒汉式 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂 ...
- PyQt5随笔:Qtdesigner设计转换而来的界面.py文件两种调用方式
PyQt5随笔:Qtdesigner设计转换而来的界面.py文件两种调用方式 文章目录 PyQt5随笔:Qtdesigner设计转换而来的界面.py文件两种调用方式 1.前言 2.方式一:另建 py ...
- 【Django】项目中调用深度学习模型model.predict()(Django两种启动方式runserver和uwsgi的区别)
目录 问题 测试 解决方法 Django两种启动方式runserver和uwsgi的区别 问题 部署含有深度学习模型的Django项目的uWSGI.Nginx服务器的时候,所有模块都可以正常运行,也可 ...
- Android service的两种使用方式bindService和startService使用方式
服务与多线程的区别: 服务仍然是运行在主线程中,而Thread则是真正的开启了一个新的线程来执行先关操作. 那为什么要用服务呢,初步理解是服务是为了更好地管理线程.试想,当我们在某一个activity ...
- C++中的两种绑定方式(静态绑定、动态绑定)
两种绑定方式 静态绑定:在编译时刻,根据指针或引用变量的静态类型来决定成员函数属于哪一个类. 动态绑定:在运行时刻,根据指针或引用变量实际指向或引用的对象类型(动态类型)来确定成员函数属于哪一个类. ...
- (C++)string 的两种输入方式和输出方式
注:头文件如下 #include<string> #include<cstdio> #include<iostream>using namespace std; 注 ...
最新文章
- 苹果被罚3.1635亿元,因不愿开放第三方支付!
- 基于VMware vSphere 5.0的服务器虚拟化实践(8)
- 基于Pytorch再次解读ResNet现代卷积神经网络
- Fabric--简单的资产Chaincode
- java继承构造_Java语言的继承结构
- php 的常量能不能删除,php能删除常量吗
- 2020年CNCF和开源项目开发速度
- kubectl apply -f_新车 | 新款捷豹F-PACE登陆广州车展!内外提升十分明显
- 《Reids 设计与实现》第十七章 发布与订阅
- Hadoop hdfs编程案例和java交互
- 网页围棋对战闪亮登场(Flex+java)
- [OMNET++]ALOHA协议
- MongoDB LBS经纬度查询操作
- js-----词法分析过程
- notebook常用快捷键
- Springboot文件上传报错:failed to convert java.lang.String to org.springframework.util.unit.DataSize
- 【JVM】JVM系列
- 树莓派应用之“魔镜”
- 公司员工阳了怎么办?
- 【47.40%】【BZOJ 1875】[SDOI2009]HH去散步
热门文章
- linux 命令行 光标移动技巧
- 微信客户端抽奖转盘效果
- Android开发者指南-用户界面-拖放-Drag and Drop[原创译文]
- php自己遇到的一些问题
- GreenDao的学习和使用
- php练手的项目,learnphp.beginmaker.com
- 如何找一个程序员做男朋友?
- 专题二:MATLAB矩阵处理
- MAC编译lame ld: symbol(s) not found for architecture x86_64/_lame_init_old“, referenced from
- configure: error: udev support requested but libudev header not installed