Qt中使用多线程常用的方式有2种
1. 继承QThread重写run函数
线程在执行过程中是不能释放线程对象的可以使用
QThread *thread = new QThread(this);
connect(thread, SIGNAL(finished()),thread ,SLOT(deleteLater()));
注意这2句代码是在主线程中执行的线程对象属于主线程,deleteLater由主线程执行,如果在子线程中创建线程对象属于子线程要考虑子线程是否还能触发信号执行槽函数
有父对象的话,父对象释放时,会来释放该子对象
class CThread : public QThread
{
public:
CThread(QObject* parent = nullptr);
~CThread();
//线程执行完毕后,运行该函数 与QThread::finished信号连接
void threadFinish();
protected:
//重写run函数 子线程会执行该函数类的代码
void run();
};
CThread::CThread(QObject* parent) : QThread(parent)
{
qDebug() << "cthread cthread";
//执行完毕后执行ThreadFinish
connect(this, &CThread::finished, this, &CThread::threadFinish);
}
CThread::~CThread()
{
qDebug() << "cthread ~cthread";
}
//我们这里重写了run函数且没有调用 QThread::exec() 函数(消息循环)子线程收到信号执行槽函数依赖消息循环 所以该线程不能收到信号执行槽函数
//打印内容后就会触发finished信号 表示线程执行完毕
void CThread::run()
{
qDebug() << "cthread run threadId: " << QThread::currentThreadId();
}
void CThread::threadFinish()
{
qDebug() << "cthread finish";
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CMainWindow w;
w.show();
CThread* pThread = new CThread();
//connect只是一个静态方法
//线程执行完毕后释放pThread对象
QObject::connect(pThread, &CThread::finished, pThread, &CThread::deleteLater);
//启动线程
pThread->start();
return a.exec();
}
输出:
main thread id: 0x1dd8
cthread cthread
cthread run threadId: 0x24e0
cthread finish
cthread ~cthread
2. moveToThread
这种方式依赖,子线程的QThread::exec() 子程序的消息循环中收到信号,执行对应的槽函数
消息循环在程序结束时如果没退出,qt会帮你退出
注意:pMyWork->moveToThread(pThread); pMyWork不能有父对象
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit CMainWindow(QWidget *parent = nullptr);
~CMainWindow();
private:
Ui::CMainWindow *ui;
signals:
void doMyWork();
};
CMainWindow::CMainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::CMainWindow)
{
ui->setupUi(this);
qDebug() << "main thread id: " << QThread::currentThreadId();
QThread* pThread = new QThread();
//QThread 的run函数里面会执行(void) exec(); 夸线程响应槽函数依赖消息循环 消息循环一般不知道子线程什么时候会执行完毕 可以使用这种方式释放线程对象
//注意这里是主线程 主线程调用deleteLater()一般没有问题, 如果线程对象属于子线程要注意子线程是否还能响应该信号
connect(pThread, &QThread::finished, pThread, &QThread::deleteLater);
CMyWork* pMyWork = new CMyWork();
//注意这里 pMyWork不能有父对象
pMyWork->moveToThread(pThread);
//触发信号后,在子线程中执行TestWork 依赖QThread::exec() 收到信号后执行
connect(this, &CMainWindow::doMyWork, pMyWork, &CMyWork::TestWork);
pThread->start();
//触发信号
emit doMyWork();
}
CMainWindow::~CMainWindow()
{
delete ui;
}
class CMyWork : public QObject
{
Q_OBJECT
public:
explicit CMyWork(QObject *parent = nullptr);
void TestWork();
signals:
public slots:
};
CMyWork::CMyWork(QObject *parent) : QObject(parent)
{
}
void CMyWork::TestWork()
{
qDebug() << "myThread testWork ThreadId" << QThread::currentThreadId();
}
输出:
main thread id: 0x43a0
myThread testWork ThreadId 0x43c0
QtConcurrent
QtConcurrent 是命名空间 (namespace),它提供了高层次的函数接口 (APIs),使所写程序,可根据计算机的 CPU 核数,自动调整运行的线程数目。
函数原型
QFuture<T> QtConcurrent::run(QThreadPool::globalInstance(), function, ...) ;
QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...);
使用准备
使用QtConcurrent需要在.pro文件增加 QT += concurrent
如果是使用VS+Qt,则需要增加模块Concurrent
#include "CMainWindow.h"
#include <QDebug>
#include <QFuture>
#include <QThread>
#include <QtConcurrent>
#include <QThreadPool>
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.pushButton, &QPushButton::clicked, this, &CMainWindow::onButtonClick);
}
void test(QString name)
{
qDebug() << name << "from" << QThread::currentThreadId();
}
void CMainWindow::onButtonClick()
{
qDebug() << "main thread" << QThread::currentThreadId();
//不给定线程池 使用QThreadPool::globalInstance()
QFuture<void> fun1 = QtConcurrent::run(test, QString("yuan"));
//等待线程执行结束
fun1.waitForFinished();
QFuture<void> fun2 = QtConcurrent::run([]()
{
qDebug() << "lambda" << QThread::currentThreadId();
});
//自定义线程池
QThreadPool threadPool;
QFuture<void> fun3 = QtConcurrent::run(&threadPool, []()
{
qDebug() << "threadPool" << QThread::currentThreadId();
});
}