文章目录
前言
在之前的Qt开发工作中,发现多线程的使用比较常见,这里将自己之前经历以及参考其它博文后获取的经验,对Qt下实现多线程的几种方式进行总结,并结合相应的示例,以便大家学习,如有错误之处,欢迎大家批评指正。
1.继承QThread,重写run()函数;
2.继承QObject,使用moveToThread()函数;
3.继承QRunnable,重写run()函数,使用QThreadPool线程池;
4.使用QtConcurrent的run()函数;
项目效果
依次点击界面上的四个groupBox中的Start按钮,可以看到下图的打印输出,通过线程号可以看到程序成功启动了四条线程,另外再次点击的话,QRunnable及QtConcurrent的方式可以再开启新的线程,所能开启的线程数量以当前线程池的设置有关。
提示:以下是本篇文章正文内容,下面案例可供参考
一、继承QThread,重写run()函数
1.qthreadrun.h
#ifndef QTHREADRUN_H
#define QTHREADRUN_H
#include <QThread>
#include <QDebug>
class QThreadRun : public QThread
{
Q_OBJECT
public:
QThreadRun();
~QThreadRun();
void setSwitch(bool flag);
void run();
private:
bool startFlag;
};
#endif // QTHREADRUN_H
2.qthreadrun.cpp
#include "qthreadrun.h"
QThreadRun::QThreadRun()
{
startFlag = false;
}
QThreadRun::~QThreadRun()
{
}
void QThreadRun::setSwitch(bool flag)
{
startFlag = flag;
}
void QThreadRun::run()
{
while(startFlag)
{
qDebug()<<"QThreadRun子线程号:"<<QThread::currentThread();
QThread::msleep(1000); //延时1000ms
}
}
二、继承QObject,使用moveToThread()函数
1.qmovetothread.h
#ifndef QMOVETOTHREAD_H
#define QMOVETOTHREAD_H
#include <QObject>
#include <QThread>
#include <QDebug>
class QMoveToThread : public QObject
{
Q_OBJECT
public:
QMoveToThread();
~QMoveToThread();
void setSwitch(bool flag);
public slots:
void slot_moveToThread();
private:
bool startFlag;
};
#endif // QMOVETOTHREAD_H
2.qmovetothread.cpp
#include "qmovetothread.h"
QMoveToThread::QMoveToThread()
{
startFlag = false;
}
QMoveToThread::~QMoveToThread()
{
}
void QMoveToThread::setSwitch(bool flag)
{
startFlag = flag;
}
void QMoveToThread::slot_moveToThread()
{
while(startFlag)
{
qDebug()<<"QMoveToThread子线程号:"<<QThread::currentThread();
QThread::msleep(1000);
}
}
三、继承QRunnable,重写run()函数,使用QThreadPool线程池
1.qrunnablerun.h
#ifndef QRUNNABLERUN_H
#define QRUNNABLERUN_H
#include <QRunnable>
#include <QThread>
#include <QDebug>
class QRunnableRun : public QRunnable
{
public:
QRunnableRun();
~QRunnableRun();
void setSwitch(bool flag);
void run();
private:
bool startFlag;
};
#endif // QRUNNABLERUN_H
2.qrunnablerun.cpp
#include "qrunnablerun.h"
QRunnableRun::QRunnableRun()
{
startFlag = false;
}
QRunnableRun::~QRunnableRun()
{
}
void QRunnableRun::setSwitch(bool flag)
{
startFlag = flag;
}
void QRunnableRun::run()
{
while(startFlag)
{
qDebug()<<"QRunnableRun子线程号:"<<QThread::currentThread();
QThread::msleep(1000);
}
}
四、使用QtConcurrent的run()函数
1.在工程文件.pro文件中添加下面这句代码
QT += concurrent
2.添加头文件
#include <QtConcurrent>
3.使用方式
...
//详细代码见下文
QtConcurrent::run(this,&Widget::myQtConcurrentRun);
...
五、示例代码
1.QThreadTest.pro
QT += core gui
QT += concurrent
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
qmovetothread.cpp \
qrunnablerun.cpp \
qthreadrun.cpp \
widget.cpp
HEADERS += \
qmovetothread.h \
qrunnablerun.h \
qthreadrun.h \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QThreadPool>
#include <QtConcurrent>
#include "qthreadrun.h"
#include "qmovetothread.h"
#include "qrunnablerun.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void initThread();
void setSwitch(bool flag);
void myQtConcurrentRun();
void myMainRun();
signals:
void signal_moveToThread();
private slots:
void on_pb_start_clicked();
void on_pb_stop_clicked();
void on_pb_start_2_clicked();
void on_pb_stop_2_clicked();
void on_pb_start_3_clicked();
void on_pb_stop_3_clicked();
void on_pb_start_4_clicked();
void on_pb_stop_4_clicked();
void on_pb_test_clicked();
private:
Ui::Widget *ui;
//QThreadRun
QThreadRun *m_QThreadRun;
//QMoveToThread
QThread *m_QThread;
QMoveToThread *m_QMoveToThread;
//QRunnableRun
QThreadPool *m_QThreadPool;
QRunnableRun *m_QRunnableRun;
//QtConcurrentRun
bool startFlag;
};
#endif // WIDGET_H
3.widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->initThread();
}
Widget::~Widget()
{
delete ui;
}
void Widget::initThread()
{
//main
qDebug()<<"Widget主线程号:"<<QThread::currentThread();
//QThreadRun
m_QThreadRun = new QThreadRun();
//QMoveToThread
m_QThread = new QThread(this);
m_QMoveToThread = new QMoveToThread();
connect(this,SIGNAL(signal_moveToThread()),m_QMoveToThread,SLOT(slot_moveToThread()),Qt::UniqueConnection);
m_QMoveToThread->moveToThread(m_QThread);
m_QThread->start();
//QRunnableRun
m_QThreadPool = new QThreadPool();
m_QThreadPool->setMaxThreadCount(3); //设置非全局线程池可容纳线程个数为3个
m_QRunnableRun = new QRunnableRun();
//QtConcurrentRun
startFlag = false;
//qDebug()<<QThreadPool::globalInstance()->maxThreadCount(); //获取全局线程池最大线程个数
//QThreadPool::globalInstance()->setMaxThreadCount(10); //设置全局线程池可容纳线程个数
}
void Widget::setSwitch(bool flag)
{
startFlag = flag;
}
void Widget::myQtConcurrentRun()
{
while(startFlag)
{
qDebug()<<"QtConcurrent子线程号"<<QThread::currentThread();
QThread::msleep(1000);
}
}
void Widget::myMainRun()
{
while(startFlag)
{
qDebug()<<"当前线程号"<<QThread::currentThread();
QThread::msleep(1000);
}
}
//QThreadRun
void Widget::on_pb_start_clicked()
{
m_QThreadRun->setSwitch(true);
m_QThreadRun->start();
}
void Widget::on_pb_stop_clicked()
{
m_QThreadRun->setSwitch(false);
}
//QMoveToThread
void Widget::on_pb_start_2_clicked()
{
m_QMoveToThread->setSwitch(true);
//m_QMoveToThread->slot_moveToThread(); 不能直接调用处理函数,函数还是在主线程中运行
emit signal_moveToThread(); //发送信号启动子线程处理函数
}
void Widget::on_pb_stop_2_clicked()
{
m_QMoveToThread->setSwitch(false);
}
//QRunnableRun
void Widget::on_pb_start_3_clicked()
{
m_QRunnableRun->setSwitch(true);
//全局线程池方式
//QThreadPool::globalInstance()->start(m_QRunnableRun);
//qDebug()<<"全局线程池当前线程数:"<<QThreadPool::globalInstance()->activeThreadCount(); //当前活动的线程个数
//非全局线程池方式
m_QThreadPool->start(m_QRunnableRun);
qDebug()<<"非全局线程池当前线程数:"<<m_QThreadPool->activeThreadCount(); //当前活动的线程个数
}
void Widget::on_pb_stop_3_clicked()
{
m_QRunnableRun->setSwitch(false);
}
//QtConcurrentRun
void Widget::on_pb_start_4_clicked()
{
setSwitch(true);
QtConcurrent::run(this,&Widget::myQtConcurrentRun);
qDebug()<<"QtConcurrentRun当前线程数:"<<QThreadPool::globalInstance()->activeThreadCount(); //当前活动的线程个数
}
void Widget::on_pb_stop_4_clicked()
{
setSwitch(false);
}
//不使用多线程的对比测试,界面卡死
void Widget::on_pb_test_clicked()
{
setSwitch(true);
myMainRun();
}
4.widget.ui
六、下载链接
我的示例百度网盘链接:https://pan.baidu.com/s/1hpcXFA2vahZ0WV3pRUfqXQ
提取码:xxcj
总结
在上述实现多线程的方法中,可以看到使用QtConcurrent的run()函数是不需要继承类,也不需要重写函数的,使用起来比较方便,需要注意的一点是,通过该方式获取的线程是来自QThreadPool池,如果QThreadPool池中没有空闲的线程,该线程可能不会直接执行。使用QRunnable的run()的时候可以看到有全局线程池和非全局线程池方式来进行start,其中的全局线程池跟QtConcurrent方法的QThreadPool是同一个,这里有几个关于线程池的函数打印:
QThreadPool::globalInstance()->maxThreadCount(); //获取线程池最大线程个数
QThreadPool::globalInstance()->setMaxThreadCount(10); //设置线程池可容纳线程个数
QThreadPool::globalInstance()->activeThreadCount(); //当前线程池活动的线程个数
有关于Qt下多线程几种方式的优缺点等详细内容,可以查看参考文章。
hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。
参考博客:
Qt的4种多线程实现方式
Qt几种多线程的实现