应用程序在某些情况下需要处理比较复杂的逻辑, 如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作,这种情况下就需要使用多线程。
Qt中使用多线程需要注意:
- Qt的默认线程为窗口线程(主线程):负责窗口事件处理或窗口控件数据的更新;
- 子线程负责后台的业务逻辑,子线程不能对窗口对象做任何操作,这些事交给窗口线程;
- 主线程和子线程之间如果进行数据的传递,需要使用信号槽机制
QT中使用线程必须使用的QThread类,而QThread的线程类常见的使用的方法如下所示:
QThread(QObject *parent = nullptr) | |
virtual | ~QThread() |
QAbstractEventDispatcher * | eventDispatcher() const |
void | exit(int returnCode = 0) 退出线程的工作函数 |
bool | isFinished() const 判断线程中的任务是否处理完毕 |
bool | isInterruptionRequested() const |
bool | isRunning() const 判断线程中的任务是否正在执行任务 |
int | loopLevel() const 返回线程的当前事件循环级别。 |
QThread::Priority | priority() const 获取当前线程优先级 |
void | 此函数可用于使长时间运行的任务完全可中断。从不检查或操作此函数返回的值是安全的,但建议在长时间运行的函数中定期这样做。注意不要太频繁地调用它,以保持低开销。 |
void | setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) |
void | setPriority(QThread::Priority priority) 设置当前线程优先级 |
void | setStackSize(uint stackSize) |
uint | stackSize() const |
bool | wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever)) 调用线程退出函数之后,线程不会马上退出,因为当前任务可能没有完成 |
bool | wait(unsigned long time) |
Public Slots
void | quit() 告诉线程的事件循环退出,返回代码0(成功)。相当于调用QThread::exit(0)。 |
void | start(QThread::Priority priority = InheritPriority) 通过调用run()开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行,则此函数不执行任何操作。 |
void | 终止线程的执行。根据操作系统的调度策略,线程可以立即终止,也可以不立即终止。在terminate()之后使用QThread::wait()来确保安全。 |
Signals
void | finished() |
void | started() |
Static Public Members
QThread * | create(Function &&f, Args &&... args) 创建新的QThread 将执行函数的对象f 与参数 |
QThread * | create(Function &&f) |
QThread * | currentThread() |
Qt::HANDLE | currentThreadId() |
int | idealThreadCount() |
void | msleep(unsigned long msecs) |
void | sleep(unsigned long secs) 强制当前线程休眠秒。 |
void | usleep(unsigned long usecs) |
void | 将当前线程的执行转换为另一个可运行线程(如果有)。请注意,操作系统决定切换到哪个线程。 |
Protected Functions
int | exec() 进入事件循环并等待直到exit(),返回传递给exit().返回的值为0,如果exit()通过调用exit(). |
virtual void | run() 线程的起点。在调用start()之后,新创建的线程调用此函数。默认实现只是调用exec()。 |
Static Protected Members
void | setTerminationEnabled(bool enabled = true) 属性启用或禁用当前线程的终止enabled 参数。线程必须由QThread. 什么时候enabled 为false,则禁用终止。未来呼叫QThread::terminate()将立即返回而不起作用。相反,终止被推迟,直到启用终止。 |
优先级:
- QThread::IdlePriority --> 最低的优先级
- QThread::LowestPriority
- QThread::LowPriority
- QThread::NormalPriority
- QThread::HighPriority
- QThread::HighestPriority
- QThread::TimeCriticalPriority
- QThread::InheritPriority --> 最高的优先级, 默认是这个
线程创建1
1.创建一个线程类的子对象,继承QThread:
2.重写父类的run()方法,在该函数内部编写子线程要处理的具体业务流程
mythread.hpp
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QObject>
class mythread : public QThread
{
Q_OBJECT
public:
explicit mythread(QObject *parent = nullptr);
protected:
void run();
signals:
void isDone();
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QDebug>
mythread::mythread(QObject *parent) : QThread(parent)
{
}
void mythread::run(){
qDebug()<<"线程启动";
QThread::sleep(5);
emit isDone();
}
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QTimer>
#include <QWidget>
#include <mythread.h>
#include <QThread>
QT_BEGIN_NAMESPACE
namespace Ui { class myWidget; }
QT_END_NAMESPACE
class myWidget : public QWidget
{
Q_OBJECT
private:
mythread *thread;
QTimer * timer;
public:
myWidget(QWidget *parent = nullptr);
~myWidget();
void dealTimeOut();
void dealDone();
void stopThread();
private slots:
void on_pushButton_clicked();
private:
Ui::myWidget *ui;
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
#include <QDebug>
myWidget::myWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::myWidget)
{
timer =new QTimer(this);
thread = new mythread(this);
// 定时器启动自动产生Timeout指令
connect(timer,&QTimer::timeout,this,&myWidget::dealTimeOut);
connect(thread,&mythread::isDone,this,&myWidget::dealDone);
connect(this,&myWidget::destroyed,this,&myWidget::stopThread);
ui->setupUi(this);
}
void myWidget::dealTimeOut(){
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
myWidget::~myWidget()
{
delete ui;
}
void myWidget::stopThread(){
thread->quit();
thread->wait();
}
void myWidget::on_pushButton_clicked()
{
if(timer->isActive()==false){
timer->start(500);
thread->start();
}
// QThread::sleep(5);
// qDebug()<<"定时器结束";
}
void myWidget::dealDone(){
qDebug()<<"it is over";
timer->stop();
}
线程创建2
class Worker : public QObject //继承自QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;//创建一个线程
public:
Controller() {
Worker *worker = new Worker;//创建一个工作对象
worker->moveToThread(&workerThread);//移动到线程种执行
//当线程执行完成后,销毁work对象
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();//开启线程
}
~Controller() {
workerThread.quit();//关闭线程
workerThread.wait();//堵塞线程
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
线程创建3
创建
QRunnable是所有可执行对象的基类,继承QRunnable类后重写其中的run()函数
,即可实现线程开发。虽然基本步骤和QThread的做法一致。但是,QRunnable不能自己运行,而是必须借助于QThreadPool
类运行
#ifndef THREAD02_H
#define THREAD02_H
#include <QRunnable>
class Thread02 : public QRunnable
{
public:
Thread02();
~Thread02();
void run() override;
};
#endif // THREAD02_H
#include "thread02.h"
#include <QThread>
#include <iostream>
using namespace std;
Thread02::Thread02()
{
cout<< "Thread01 construct fun" << QThread::currentThread() << endl;
}
Thread02::~Thread02()
{
cout<< "Thread01 destructor fun" << QThread::currentThread() << endl;
}
void Thread02::run()
{
cout<< "Thread02 construct fun" << QThread::currentThread() << endl;
}
启动
线程的启动方法如下:
#include <QCoreApplication>
#include "thread02.h"
#include <iostream>
#include <QThreadPool>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<< "main thread" << QThread::currentThread() << endl;
/* Thread01 th;
th.start();*/
Thread02 *th = new Thread02();
QThreadPool::globalInstance()->start(th);
cout<< "main thread end" << endl;
return a.exec();
}
QThreadPool线程池
QThreadPool管理和回收单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问。
要使用其中一个QThreadPool线程,请子类化QRunnable并实现run()虚拟函数。然后创建该类的对象并将其传递给QThreadPool::start()。
class HelloWorldTask : public QRunnable
{
void run() override
{
qDebug() << "Hello world from thread" << QThread::currentThread();
}
};
HelloWorldTask *hello = new HelloWorldTask();
// QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool::globalInstance()->start(hello);
Properties
- activeThreadCount : const int 此属性表示线程池中的活动线程数
- expiryTimeout : int 在expiryTimeout毫秒内未使用的线程被认为已过期并将退出。此类线程将根据需要重新启动。默认的expiryTimeout为30000毫秒(30秒)
- maxThreadCount : int 此属性表示线程池使用的最大线程数。
- stackSize : uint 此属性包含线程池工作线程的堆栈大小。
Public Functions公共职能
QThreadPool(QObject *parent = nullptr) | |
virtual | ~QThreadPool() |
int | activeThreadCount() const 此属性表示线程池中的活动线程数 |
void | clear() 从队列中移除尚未启动的可运行对象。runnable->autoDelete()返回 |
bool | contains(const QThread *thread) const 如果thread是由这个线程池管理的线程,则返回 |
int | expiryTimeout() const |
int | maxThreadCount() const 此属性表示线程池使用的最大线程数 |
void | 释放先前通过调用reserveThread()保留的线程。 |
void | 保留一个线程,忽略activeThreadCount()和maxThreadCount()。 |
void | setExpiryTimeout(int expiryTimeout) |
void | setMaxThreadCount(int maxThreadCount) 设置最大线程数量 |
void | setStackSize(uint stackSize) |
uint | stackSize() const 此属性包含线程池工作线程的堆栈大小。 |
void | start(QRunnable *runnable, int priority = 0) 入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable |
void | start(std::function<void ()> functionToRun, int priority = 0) |
bool | tryStart(QRunnable *runnable) 尝试启动一个 |
bool | tryStart(std::function<void ()> functionToRun) |
bool | tryTake(QRunnable *runnable) 删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功 |
bool | waitForDone(int msecs = -1) 等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出 |
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QRunnable>
#include <QObject>
#include <QDebug>
#include <QReadWriteLock>
#include <QTime>
#include <QSemaphore>
class mythread : public QObject, public QRunnable
{
Q_OBJECT
public:
mythread();
//QThread的虚函数
//线程处理函数
//不能直接调用,通过start()间接调用
void run();
signals:
void isDone(int); //处理完成信号
void mySignal(); //注意!要使用信号,采用QObejct 和 QRunnable多继承,记得QObject要放在前面
public slots:
//接收主线程的消息
void recMegFromMain(QString);
};
class mythread1 : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
};
class mythread2 : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
};
class mythread3 : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
};
class mythread4 : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QMutex>
#include <QRandomGenerator>
#include <QWaitCondition>
#include <QThread>
/*
如果乱码就加上QStringLiteral();
#pragma execution_character_set("GB2312")
*/
mythread::mythread()
{
}
void mythread::run()
{
for(int i=0;i<10;i++){
//QThread::sleep(2);
qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() << QStringLiteral( " 线程1打印数据:") <<QString::number(i);
}
//emit isDone(1); //发送完成信号
}
void mythread::recMegFromMain(QString str)
{
qDebug()<< "子线程接收到" <<str;
}
void mythread1::run()
{
qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() ;
for(int i=10;i<20;i++){
QThread::sleep(2);
qDebug()<< "线程2打印数据:" <<QString::number(i);
}
//emit isDone(1); //发送完成信号
}
void mythread2::run()
{
qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
for(int i=20;i<30;i++){
QThread::sleep(2);
qDebug()<< "线程3打印数据:" <<QString::number(i);
}
//emit isDone(1); //发送完成信号
}
void mythread3::run()
{
qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
for(int i=30;i<40;i++){
QThread::sleep(2);
qDebug()<< "线程4打印数据:" <<QString::number(i);
}
//emit isDone(1); //发送完成信号
}
void mythread4::run()
{
qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
for(int i=40;i<50;i++){
QThread::sleep(2);
qDebug()<< "线程5打印数据:" <<QString::number(i);
}
//emit isDone(1); //发送完成信号
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "mythread.h"
#include <QDebug>
#include <QMessageBox>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void dealDone(); //线程槽函数
void mySlot();
void receiveMsgFromThread(int);
void sengMsgToThreadBtn();
private:
Ui::MainWindow *ui;
QThreadPool pool;
mythread* task = new mythread();
mythread1* task1 = new mythread1();
mythread2* task2 = new mythread2();
mythread3* task3 = new mythread3();
mythread4* task4 = new mythread4();
signals:
//给子线程发消息
void sengMsgToThread(QString);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_pushButton_6_clicked();
void on_pushButton_7_clicked();
void on_pushButton_8_clicked();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QReadWriteLock>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置最大线程数为3的一个线程池
pool.setMaxThreadCount(5);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::sengMsgToThreadBtn()
{
emit sengMsgToThread("hello");
}
// 定义槽函数 mySlot()
void MainWindow::mySlot()
{
QMessageBox::about(this,"Tsignal", "响应线程中的mySlot函数");
}
//接收线程函数
void MainWindow::receiveMsgFromThread(int i)
{
QString str = QString::number(i);
qDebug()<<str;
}
void MainWindow::dealDone()
{
ui->label->setText("线程停止");
//停止线程
}
void MainWindow::on_pushButton_clicked()
{
//QThread::sleep(1);
//pool.waitForDone(); //等待任务结束
on_pushButton_4_clicked();
on_pushButton_5_clicked();
on_pushButton_6_clicked();
on_pushButton_7_clicked();
on_pushButton_8_clicked();
//启动线程,处理数据
ui->label->setText("start");
}
void MainWindow::on_pushButton_2_clicked()
{
//pool.releaseThread();
//停止线程
//dealDone();
//sengMsgToThreadBtn();
}
void MainWindow::on_pushButton_3_clicked()
{
qDebug() <<pool.activeThreadCount();
//sengMsgToThreadBtn();
}
void MainWindow::on_pushButton_4_clicked()
{
pool.start(task); //任务放进线程池
task->setAutoDelete(false);
}
void MainWindow::on_pushButton_5_clicked()
{
pool.start(task); //任务放进线程池
task->setAutoDelete(false);
/*
pool.start(task1);
task1->setAutoDelete(false);
*/
}
void MainWindow::on_pushButton_6_clicked()
{
pool.start(task); //任务放进线程池
//pool.start(task2);
}
void MainWindow::on_pushButton_7_clicked()
{
pool.start(task); //任务放进线程池
//pool.start(task3);
}
void MainWindow::on_pushButton_8_clicked()
{
pool.start(task); //任务放进线程池
//pool.start(task4);
}