Qt 多线程 互斥锁使用小结

文章介绍了在Qt中创建多线程的两种方法,包括继承QThread和使用moveToThread()。还详细讲解了如何使用互斥锁QMutex确保线程安全,防止并发访问同一变量时出错。通过示例代码展示了线程同步和数据共享的实现。
摘要由CSDN通过智能技术生成

目录

一、创建多线程

方式1:

方式2:

二、Qt中互斥锁的使用

代码:

pidcontroller.h

pidcontroller.cpp

widget.cpp


在这个视频学的:

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; //分配空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值