qt多线程的有什么用?
将耗时长的操作丢入专属线程执行,这样就不会影响主线程的界面操作,操作完再用信号槽等的方式返回结果
1.界面和部件相关都必须在主界面运行,不要用子线程调用或者操作,会引起奇怪的bug,子线程通过信号槽操作界面返回结果
2.线程转移不允许有父对象的线程转移,可能是因为父对象对象树销毁时无法保证子对象线程安全
3.对象必须包含QOBJECT
下面用两种方法介绍多线程的使用方法
假设有一种算法非常耗时,要消耗2s,我们设计一个界面求计算后的结果
经典方法:
转到按键信号槽,调用
当你计算的时候就会惊奇的发现,点击计算后计算完成前界面动不了了,连关都关不掉,点快了甚至还会无响应,因为所有gui相关组件和界面都在且只能在主线程进行
为了更直观的表现,我们修改一下代码,使用QThread::currentThreadID()看看主线程和执行算法的线程ID
可以看到算法是在主线程执行的,所以才会导致界面在执行算法中无法操作
为了防止出现这样的问题,采用子线程执行,这样就不会影响界面的操作,有两种方法
1.重写run
建立一个类,继承QThread,初步重写run函数
在QT中,对象与对象之间都是new的,所以无法相互调用,对象间操作都要通过信号槽或者元对象系统访问,我们的算法也不例外,算法对象由widget创立,需要通过信号槽完成算法对象对widget对象的数据结果返回(所以要继承QOBJECT),添加算法类内容
重写run的多线程方式有点像动态线程,即取即用
1,按键按下的槽函数
建立算法对象赋值,连接算法返回值槽函数,算法对象调用start函数
注意:重写的run函数为start()后新线程自动执行的函数,run函数执行完成后线程结束销毁
你可以直接调用run方法,仍会执行run函数内容,但是只会在调用run的线程里执行run的内容,不会创建新线程执行run内容,只能通过调用start方法才能真正在新线程里执行run函数的内容。
2.算法的run函数
因为算法没有绑定父对象,所以让它执行完后自己释放自己的内存
打印的槽函数:
执行 输入值后连点两次计算看看
发现连点两次创造了两个线程,我们的算法在线程里执行,如果是单线程执行第二次点的时候就直接卡死了。稍等一下结果出来后再点击一下计算看看
线程run函数执行完后释放,所以第三次点击的时候第一次和第二次的线程已经销毁了,可以又从第一次的线程ID创建,可以在run函数最后加上while(1)或者exec看看是否会释放
2.moveToThread
moveToThread更倾向于将计算丢进一个长期存在的算法线程,所以对构造函数进行改变并且在widget构造时就新建此线程,且不退出
创建一个简单的线程类对象
在主线程中创建这个类的对象并start,连接算法对象的接收发送信号槽,最后将算法对象移动到创建的线程对象
执行,点击两下计算,会发现一开始只打印了一次,因为此时算法线程在执行第一个信号槽函数的QThread::sleep,所以信号在事件里等待,然后过2s后第二个信号执行。两次的算法线程一致