目录
在这个视频学的:
Qt中多线程-线程池的使用-C/C++/qt_哔哩哔哩_bilibili
代码资源见网盘:
链接:https://pan.baidu.com/s/1PKN7PvY_H2u8MAxqnXts7w
提取码:off0
一、创建多线程
创建多线程一般有两种方式:一是继承Qt线程类QThread,重写run()方法;二是创建线程类,构造公共成员函数,主线程中使用moveToThread()方法
方式1:
1.创建一个类,继承QThread,例如
class Generate : public QThread
{
Q_OBJECT
public:
explicit Generate(QObject *parent = nullptr);
void recvNum(int num);
protected:
void run() override;
signals:
void sendArray(QVector<int> num);
private:
int m_num;
};
2.重写run()函数,里面是具体多线程处理的业务
void Generate::run()
{
qDebug() << "生成随机数的线程的线程地址:"<< QThread::currentThread();
QVector<int> list;
QElapsedTimer time;
time.start();
for(int i=0; i<m_num; i++)
{
list.push_back(qrand()% 100000);
}
int milsec = time.elapsed();
qDebug()<< "生成" << m_num << "个随机数总共用时:"<< milsec << "毫秒";
emit sendArray(list);
}
3.在主线程中创建子线程对象
Generate* gen = new Generate;
4.启动子线程,调用start()方法。注意不能在类外调用run()方法。调用start()后,线程开始运行了
gen->start();
方式2:
1.创建一个类,让这个类从QObject派生
2.在这个类中添加公有成员函数,函数体UpdateData1(int *i)就是我们多线程要执行的任务
class Pidcontrollor : public QObject
{
Q_OBJECT
public:
explicit Pidcontrollor(QObject *parent = nullptr);
void UpdateData1(int *i);
static QMutex mutex;
private:
signals:
void finish();
};
3.在主线程中创建QThread对象,这就是等会儿要加入的子线程的对象
QThread* t1 = new QThread(this);//指定父对象this,程序结束自动析构线程对象
4.在主线程中创建工作的类对象(千万不要指定父对象!)
Pidcontrollor * pid1 = new Pidcontrollor;
5.将pid1对象移动到创建的子线程对象中,需要调用QObject类提供的moveToThread()方法(这是为什么要继承与QObject的原因)
pid1->moveToThread(t1);
6.启动子线程,调用start()线程启动了,但是对象并没有开始工作
t1->start();
7.调用类对象的工作函数,让这个函数开始执行,这个时候函数是移动到子线程中执行的,可以使用信号和槽进行调用和传参
connect(this, &Widget::starting, pid1, &Pidcontrollor::UpdateData1);
二、Qt中互斥锁的使用
互斥锁是用来保证多个线程同时访问或修改同一变量不出错。使用时需要引用QMutex类。本文采用两个线程同时访问主线程的变量,每个线程对变量进行100000次的加,最终验证该变量是否为200000.
代码:
pidcontroller.h
ifndef PIDCONTROLLOR_H
#define PIDCONTROLLOR_H
#include <QObject>
#include <QMutex>
class Pidcontrollor : public QObject
{
Q_OBJECT
public:
explicit Pidcontrollor(QObject *parent = nullptr);
void UpdateData1(int *i);
void UpdateData2(int *i);
static QMutex mutex;
private:
signals:
void finish();
};
#endif // PIDCONTROLLOR_H
pidcontroller.cpp
include "pidcontrollor.h"
Pidcontrollor::Pidcontrollor(QObject *parent) : QObject(parent)
{
}
void Pidcontrollor::UpdateData2(int *i)
{
for(int j=0;j<100000;j++)
{
mutex.lock();
*i = *i+1;
mutex.unlock();
}
emit finish();
}
void Pidcontrollor::UpdateData1(int *i)
{
for(int j=0;j<100000;j++)
{
mutex.lock();
*i = *i+1;
mutex.unlock();
}
emit finish();
}
QMutex Pidcontrollor::mutex; //分配空间
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "pidcontrollor.h"
#include <QThread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//1.创建子线程对象
QThread* t1 = new QThread(this);//指定父对象this,程序结束自动析构线程对象
QThread* t2 = new QThread;
//2. 创建任务类对象
Pidcontrollor * pid1 = new Pidcontrollor;
Pidcontrollor * pid2 = new Pidcontrollor;
pid1->moveToThread(t1);
pid2->moveToThread(t2);
connect(ui->start, &QPushButton::clicked,this,[=]()
{
emit starting(&num);
t1->start();
t2->start();
});
connect(this, &Widget::starting, pid1, &Pidcontrollor::UpdateData1);
connect(this, &Widget::starting, pid2, &Pidcontrollor::UpdateData1);
connect(pid1,&Pidcontrollor::finish,this,[=]()
{
ui->lineEdit->setText(QString::number(num));
});
connect(pid2,&Pidcontrollor::finish,this,[=]()
{
ui->lineEdit->setText(QString::number(num));
});
}
Widget::~Widget()
{
delete ui;
}
注意事项:
1.信号参数模板定义:
非Qt基本类型的参数需要使用qRegisterMetaType函数进行创建类型,且只能是指针不能是引用;
qRegisterMetaType<int*>("int*");
2.采用静态成员变量定义mutex实现多对象线程使用同一互斥锁:
要保证多个对象使用同一个互斥锁,需要将互斥锁定义成静态成员对象,且在.cpp文件中给对象分配空间。
static QMutex mutex;
cpp:
QMutex Pidcontrollor::mutex; //分配空间