QT实际是有两种线程写法的:
第一种就是常见的写法:继承QThread类,重写run函数,把需要子线程执行的任务放在run函数中,调用start,线程开始执行。
这种写法有个缺点就是:需要线程执行的任务都要放在run函数中,如果你在run中放一个signal,通知run函数外的槽函数执行某个操作,那么这个槽函数就会在主线程中执行(即使这个槽函数是在子线程类中的,也会在主线程中执行)。这对于使用信号槽方式的QT来说是无法接受的,因此QT强烈建议大家不要使用这种方式。
另外一种就是QT推荐的moveToThread写法:定义一个继承QObject的类,在类中定义一个槽函数,在槽函数中定义线程需要做的工作。
乍一看,和第一种没啥区别是吧,那么我们让这个槽函数发出一个信号出来,看下结果:
mainwindow.cpp文件:由它启动子线程
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, mThread(new mthread)
{
ui->setupUi(this);
connect(mThread,&mthread::signal_send,mThread,&mthread::slot_get_send);
qDebug() << "mainwindow threadID : "<< QThread::currentThread();
QThread *thread = new QThread;//新建的QThread类
mThread->moveToThread(thread);//把继承QObject的类moveToThread,放到线程thread中
thread->start();//调用线程的start方法
mThread->creatThread();//让子线程发出开始工作的信号
}
mthread.h文件:
#include <QObject>
class mthread : public QObject
{
Q_OBJECT
public:
explicit mthread(QObject *parent = nullptr);
void creatThread();
signals:
void signal_send();
void signal_test_signal();
public slots:
void slot_get_send();
void slot_test_signal();
};
mthread.cpp文件:
#include "mthread.h"
#include "QThread"
#include "QDebug"
mthread::mthread(QObject *parent) : QObject(parent)
{
connect(this,&mthread::signal_test_signal,this,&mthread::slot_test_signal);
}
void mthread::creatThread()
{
emit signal_send();
qDebug() << "creatThread threadID : "<< QThread::currentThread();
}
void mthread::slot_get_send()
{
qDebug() << "slot_get_send threadID : "<< QThread::currentThread();
emit signal_test_signal();
}
void mthread::slot_test_signal()
{
qDebug() << "slot_test_signal threadID : "<< QThread::currentThread();
}
结果如下:
mainwindow threadID : QThread(0x230de578580)
creatThread threadID : QThread(0x230de578580)
slot_get_send threadID : QThread(0x230e1404ba0)
slot_test_signal threadID : QThread(0x230e1404ba0)
主线程和子线程中的发出信号的函数都在主线程中,子线程中的两个槽函数都在子线程中运行。
这就告诉我们moveToThread的两个特点:
1.槽函数才是执行子线程工作的地方,千万不要在其他非槽函数的函数中写子线程工作!!(哪怕这些非槽函数就在子线程类中)
2.子线程类中的槽函数都在子线程中运行!
其实QT的线程写法加上它的信号槽,还创建了一个比较方便的工作:可以在一个类中定义很多个任务,然后发出不同的信号,子线程就可以执行不同的槽函数。相比于继承QThread只能执行run()函数中的一个任务,moveToThread的方法中一个线程可以做很多不同的工作。
mainwindow.cpp文件新增:
connect(this,&MainWindow::signal_mainwindow,mThread,&mthread::slot_mainwindows);
//mThread->creatThread();//原来的信号屏蔽掉
emit signal_mainwindow();//mainwindow中增加新的信号signal_mainwindow
mThread.cpp文件新增:
void mthread::slot_mainwindows()
{
qDebug() << "slot_mainwindows threadID : "<< QThread::currentThread();//新加一个参函数
}
运行结果:
mainwindow threadID : QThread(0x1af20d1ab90)
slot_mainwindows threadID : QThread(0x1af20d50c70)
所以总的来说:
1.如果选择——继承QThread类,重写run函数。请把所有需要子线程处理的事务都放在run函数中
2.如果选择——moveToThread。请把所有需要子线程处理的事务都放在槽函数中。(切记!切记!槽函数!)
1)子线程类中的槽函数都在子线程中运行,所以你可以在子线程中任意跳转参函数
2)可以在一个类中定义很多个任务,然后发出不同的信号,子线程就可以执行不同的槽函数