Qt中主线程负责界面显示和窗口控件的数据更新,子线程负责逻辑业务处理和数据计算,子线程不能对窗口有任何操作,子线程可通过信号槽来将数据传递给主线程。
1、子线程继承QThread
子线程继承QThread,然后重写run()函数来执行子线程
每一个子业务逻辑都可继承一个QThread来实现多线程
m_thread = new MyThread;
connect(m_thread, &MyThread::signalsThreadCalNum, this, [=](int num){
ui->label->setNum(num);
});
connect(ui->pushButton_start, &QPushButton::clicked, m_thread, [=](){
m_thread->start();
});
connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
m_thread->Stop();
});
class MyThread:public QThread
{
Q_OBJECT
//....
protected:
void run();
}
void MyThread::run()
{
int n = 0;
while(n < 100000)
{
emit signalsThreadCalNum(n++);
QThread::usleep(1);
}
}
2、使用moveToThread
(1)任务类Task需要继承QObject,然后写一个执行任务的函数。
(2)创建一个QThread线程,然后调用moveToThread将对象移动到创建的子线程对象中
(3)启动子线程即可
//创建子线程
m_thread = new QThread;
m_work = new MyWork;
//将工作的类对象转移到创建的子线程对象中
m_work->moveToThread(m_thread);
//启动线程
m_thread->start();
//这种写法是错误的,界面卡顿,个人理解:接受者是this,相当于mainwiodnw调用
// connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
// m_work->Work();
// });
//ok
connect(ui->pushButton_start, &QPushButton::clicked, m_work, [=](){
m_work->Start();
});
connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
m_work->Stop();
});
connect(m_work, &MyWork::signalsThreadCalNum, this, [=](int num){
ui->label->setNum(num);
});
class MyWork:public QObject
{
//......
}
void MyWork::Work()
{
int n = 0;
while(n < 1000)
{
if(m_stop)
break;
emit signalsThreadCalNum(n++);
QThread::usleep(1);
}
}
3、使用QtConcurrent
(1)pro中需要加上 QT += concurrent
(2)任务类中重写run()函数
MyThread *mythread = new MyThread;
connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
QtConcurrent::run(mythread, &MyThread::Work);
});
connect(mythread, &MyThread::signalsThreadCalNum, this, [=](int num){
ui->label->setNum(num);
});
connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
mythread->Stop();
});
void MyThread::Work()
{
m_stop = false;
int n = 0;
while(n < 100000)
{
if(m_stop)
break;
emit signalsThreadCalNum(n++);
QThread::usleep(1);
}
}
4、使用线程池
使用QRunnable和QThreadPool
(1)任务类需要继承QRunnable,需要使用信号槽的话可多重继承QObject
(2)重写run函数
(3)使用QThreadPool::globalInstance()->start(QRunable *)来启动线程池
// 线程池初始化,设置最大线程池数
QThreadPool::globalInstance()->setMaxThreadCount(4);
//创建任务
MyThread *mythread = new MyThread;
//start启动线程池
connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
QThreadPool::globalInstance()->start(mythread);
mythread->Start();
});
connect(mythread, &MyThread::signalsThreadCalNum, this, [=](int num){
ui->label->setNum(num);
});
connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
mythread->Stop();
});
/*
* 线程池使用需要继承QRunnable
*/
class MyThread : public QObject, public QRunnable
{
//.....
}
MyThread::MyThread(QObject *parent) : QObject(parent), QRunnable()
{
setAutoDelete(true);
}
void MyThread::run()
{
m_stop = false;
int n = 0;
while(n < 100000)
{
if(m_stop)
break;
emit signalsThreadCalNum(n++);
QThread::usleep(1);
}
}
5、线程池中可不采用多重继承QObject,可采用
QMetaObject::invokeMethod来实现
mainwindow.h中添加
Q_INVOKABLE void Show(int num);
mainwindow.cpp
//mainwindow.cpp
// 线程池初始化,设置最大线程池数
QThreadPool::globalInstance()->setMaxThreadCount(4);
//创建任务
MyThread *mythread = new MyThread(this);
//start启动线程池
connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
QThreadPool::globalInstance()->start(mythread);
mythread->Start();
});
connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
mythread->Stop();
});
void MainWindow::Show(int num)
{
ui->label->setNum(num);
}
子线程中
void MyThread::run()
{
m_stop = false;
int n = 0;
while(n < 100000)
{
// if(m_stop)
// break;
QMetaObject::invokeMethod(m_pObj, "Show", Q_ARG(int, n++));
//emit signalsThreadCalNum(n++);
QThread::usleep(1);
}
}