Qt自有的和线程有关的函数和类

前言

通常情况下,应用程序都是在一个线程中执行操作。但是,当调用一个耗时操作(例如,大批量I/O或大量矩阵变换等CPU密集操作)时,用户界面常常会冻结。而使用
多线程可解决这一问题。
多线程具有以下几点优势。
(1)提高应用程序的响应速度。这对于开发图形界面的程序尤为重要,当一个操作耗时很长时,整个系统都会等待这个操作,程序就不能响应键盘、鼠标、菜单等的操
作,而是使用了多线程技术可将耗时长的操作置于一个新的线程,从而避免以上的问题。
(2)使多CPU系统更加有效。当线程数不大于CPU数目时,操作系统可以调度不同的线程运行于不同的CPU上。
(3)改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为独立或半独立的运行部分,这样有利于代码的理解和维护。
多线程程序有以下几个特点。
(1)多线程程序的行为无法预期,当多次执行上述程序时,每一次的运行结构都可能不同。
(2)多线程的执行顺序无法保证,它与操作系统的调度策略和线程优先级等因素有关。
(3)多线程的切换可能发生在任何时刻、任何地点。
(4)多线程对代码的敏感度高,因此对代码的细微修改都可能产生意想不到的结果。
基于以上这些特点,为了有效地使用线程,开发人员必须对其进行控制。

QT越发强大起来,本文主要总结Qt本身有的实现多线程的方法,以及自带的实现线程间同步的函数
Qt中有两种实现多线程的方式:
1、继承QThread,然后重写run函数实现多线程
2、继承QObject,使用moveToThread函数实现多线程
3、使用QThreadPool线程池,搭配QRunnable
4、使用QtConcurrent
官方推荐使用第二种方法实现多线程

QT中线程之间的同步问题,可以分为互斥、锁、信号量、条件变量四大方面,每个方面都有自己的优缺点:
QMutex、QMutexLocker、QReadWriteLocker、QReadLocker、QWriteLocker、QSemaphore和QWaitCondition。

一、四中线程实现的原理和优缺点

1.QThread类的run

一、实现方法:新建一个集成QThread的类,重写虚函数run,通过run启动线程
二、特点:
1、优点:可以通过信号槽与外界进行通信。
2、缺点:1每次新建一个线程都需要继承QThread,实现一个新类,使用不太方便。要自己进行资源管理,线程释放和删除。并且频繁的创建和释放会带来比较大的内存开销,所以对于线程数较少的通常会用这种方法
3、适用场景:QThread适用于那些常驻内存的任务。

2.QThread类的moveToThread

一、实现方法:让一个类继承QObject的A,然后在主线程中new一个QThread(或者其他继承QThread类的),通过moveToThread:类似
A->moveToThread(&Thread)
二、特点:
moveToThread对比传统子类化Qthread更灵活,仅需要把你想要执行的代码放到槽,movetothread这个object到线程,然后拿一个信号连接到这个槽就可以让这个槽函数在线程里执行。这样通过信号与曹的方式,将主线程需要执行的槽函数全部可以转到另外一个线程中去,比起第一种方法来说,更灵活(当然注意链接的时候connect第五个参数的含义),movetothread给我们编写代码提供了新的思路,当然不是说子类化qthread不好,只是你应该知道还有这种方式去调用线程。
轻量级的函数可以用movethread,多个短小精悍能返回快速的线程函数适用 ,无需创建独立线程类,例如你有20个小函数要在线程内做, 全部扔给一个QThread。而我觉得movetothread和子类化QThread的区别不大,更可能是使用习惯引导。又或者你一开始没使用线程,但是后边发觉这些代码还是放线程比较好,如果用子类化QThread的方法重新设计代码,将会有可能让你把这一段推到重来,这个时候,moveThread的好处就来了,你可以把这段代码的从属着movetothread,把代码移到槽函数,用信号触发它就行了。其它的话movetothread它的效果和子类化QThread的效果是一样的,槽就相当于你的run()函数,你往run()里塞什么代码,就可以往槽里塞什么代码,子类化QThread的线程只可以有一个入口就是run(),而movetothread就有很多触发的入口。

3.QRunnalble的run

第三个和第四个都属于高级用法了,算是在使用中更方便。
Qrunnable是所有可执行对象的基类。我们可以继承Qrunnable,并重写虚函数void QRunnable::run () 。我们可以用QThreadPool让我们的一个QRunnable对象在另外的线程中运行,如果autoDelete()返回true(默认),那么QThreadPool将会在run()运行结束后自动删除Qrunnable对象。可以调用void QRunnable::setAutoDelete ( bool autoDelete )更改auto-deletion标记。需要注意的是,必须在调用QThreadPool::start()之前设置,在调用QThreadPool::start()之后设置的结果是未定义的。
一、实现方法:
1、继承QRunnable。和QThread使用一样, 首先需要将你的线程类继承于QRunnable。
2、重写run函数。还是和QThread一样,需要重写run函数,run是一个纯虚函数,必须重写。
3、使用QThreadPool启动线程
二、特点:
优点:无需手动释放资源,QThreadPool启动线程执行完成后会自动释放。
缺点:不能使用信号槽与外界通信。
适用场景:QRunnable适用于线程任务量比较大,需要频繁创建线程。QRunnable能有效减少内存开销。

4.QtConcurrent的run

Concurrent是并发的意思,QtConcurrent是一个命名空间,提供了一些高级的 API,使得在编写多线程的时候,无需使用低级线程原语,如读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展。
QtConcurrent::run能够方便快捷的将任务丢到子线程中去执行,无需继承任何类,也不需要重写函数,使用非常简单。详见前面的文章介绍,这里不再赘述。
需要注意的是,由于该线程取自全局线程池QThreadPool,函数不能立马执行,需要等待线程可用时才会运行。
一、实现方法:
1、首先在.pro文件中加上以下内容:QT += concurrent
2、包含头文件#include ,然后就可以使用QtConcurrent了
QFuture fut1 = QtConcurrent::run(func, QString(“Thread 1”)); fut1.waitForFinished();
三、特点:
//调用外部函数 QFuture f1 =QtConcurrent::run(func,QString(“aaa”));
//调用类成员函数 QFuture f2 =QtConcurrent::run(this,&MainWindow::myFunc,QString(“bbb”));
要为其指定线程池,可以将线程池的指针作为第一个参数传递进去
向该函数传递参数,需要传递的参数,则跟在函数名之后
可以用run函数的返回值funIr来控制线程。
如: funIr.waitForFinished(); 等待线程结束,实现阻塞。
funIr.isFinished() 判断线程是否结束
funIr, isRunning() 判断线程是否在运行
funIr的类型必须和线程函数的返回值类型相同,可以通过
funIr.result() 取出线程函数的返回值
缺点:不能直接用信号和槽函数来操作线程函数,eg : 当线程函数结束时,不会触发任何信号。
参考文章:多线程QtConcurrent的详细用法

二、线程间同步

三、代码实例

1.代码1

2.代码2

3.代码3

4.代码4

总结

QT中的多线程函数和线程之间的同步函数已经很全了,在使用过程中如果不清楚可以查看相应的手册。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的挖掘机

谢谢大家的厚爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值