14 Qt多线程
Qt中使用多线程的方法
1.Qt中使用多线程的注意事项
Qt默认是单线程的,MainWindow的那个线程就是主线程,也被称为UI线程
子线程只负责业务逻辑、数据的处理,不能越级对主线程(UI线程)中显示的UI界面进行操作
主线程如果要和子线程进行数据交互,要使用信号槽
2.QThread类
QThread
类继承自QObject
,可以把它看成一个QObject
,只不过多了个把某个成员函数放到子线程内运行的能力,而且既然他是QObject
的子类,他也可以使用信号槽那些东西。
2.1run()方法
QThread类本身不是线程,实际上它只有调用
start()
后才会创建一个新的线程,然后把run()
函数丢到这个新的线程中运行。==正常情况下,只有QThread类的run()函数才会在子线程中运行,其他的比如槽函数,都不在子线程中==
这个是多线程的核心,它是Qt在创建的子线程中所执行的任务
这个函数是个虚函数,也就是说我们得创建QThread的子类并重新这个方法才行
这个函数的属性是Protected,我们只能调用
start()
方法来开启子线程对run()
函数的执行
2.2线程ID
写Qt多线程 + 槽函数时,在调试阶段一定要在子线程中输出线程ID试试,免得写了半天结果槽函数没在子线程中运行
法一:直接输出运行该行代码的线程的ID
1 | void run() |
法二:输出某变量所属线程的ID
1 | test_thread *t1 = new test_thread(); |
3.Qt使用子线程的方法
- Qt中有2种多线程编程的方法,且各有优势
法一、继承QThread,并重写run()函数
这是最常见的使用多线程的方法,run()
中的业务逻辑会被放到子线程中使用
该方法包括以下缺点:
- 假设要在一个子线程中处理多个任务,所有的处理逻辑都需要写到run()函数中,这样该函数中的处理逻辑就会变得非常混乱,不太容易维护
法二、继承QObject
1.创建一个新的类,让这个类从QObject派生
1 | class MyWork:public QObject |
2.在这个类中添加一个公共的成员函数,函数体就是我们要子线程中执行的业务逻辑
1 | class MyWork:public QObject |
3.在主线程中创建一个QThread对象, 这就是子线程的对象QThread* sub = new QThread;
4.在主线程中创建工作的类对象(千万不要指定给创建的对象指定父对象)
1 | MyWork* work = new MyWork(this); // error |
5.将MyWork对象移动到创建的子线程对象中, 需要调用QObject类提供的moveToThread()方法
1 | // void QObject::moveToThread(QThread *targetThread); |
6.启动子线程,调用 start(), 这时候线程启动了, 但是移动到线程中的对象并没有工作
7.调用MyWork类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的
1 | // 让工作的对象开始工作, 点击开始按钮, 开始工作 |
必须使用信号槽的方式来调用
working()
函数,不能直接调用
使用这种多线程方式,假设有多个不相关的业务流程需要放在子线程中被处理,那么就可以创建多个类似于MyWork的类,将业务流程放多类的公共成员函数中,然后将这个业务类的实例对象移动到对应的子线程中moveToThread()就可以了。这样就可实现在一个线程对象中做不同的任务