Qt互斥锁(QMutex)的使用、QMutexLocker的使用

Qt互斥锁【QMutex】的使用、QMutexLocker的使用

  • Chapter1 Qt互斥锁(QMutex)的使用、QMutexLocker的使用
    • 一、QMutexLocker和QMutex实现示例图
    • 二、QMutex和QMutexLocker的关系(个人理解)
    • 三、QMutex使用和QMutexLocker使用
      • 1.QMutex的使用
      • 2.QMutexLocker的使用
    • 四、检验QMutexLocker是否将传入的互斥锁锁定
      • 1.操作解释
      • 2.CMoveFuncClass(使用moveToThread实现,使用QMutexLocker)
      • 3.CThread类(继承QThread实现,单纯使用QMutex)
      • 4.CMainWindow调用类
    • 总结
    • 相关文章


Chapter1 Qt互斥锁(QMutex)的使用、QMutexLocker的使用

原文链接:https://blog.csdn.net/wj584652425/article/details/123585126

一、QMutexLocker和QMutex实现示例图

下图为检测QMutexLocker是否上锁成功的示例图(两个线程使用同一个QMutex),源码在文章第四节(源码含详细注释)。

下图为不同QMutex运行时的效果(该图表明两个线程无关,并非sleep影响了另一个线程的运行)

二、QMutex和QMutexLocker的关系(个人理解)

互斥锁(QMutex)在使用时需要在进入和结束的时候使用对应的函数锁定和解锁。在简单的程序中还好,但是在结构复杂的程序中因为需要手动锁定和解锁,很容易忽略细节而出现问题,于是为了应对这种情况QMutexLocker便诞生了(为了简化简化互斥锁的锁定和解锁)。
QMutexLocker通常创建为局部变量,QMutexLocker在创建时传入一个并未锁定(若是锁定可用relock重新锁定或unlock解锁)的QMutex指针变量,并且会将QMutex变量锁定,在释放时会将QMutex变量解锁。(QMutexLocker创建时将传入的QMutex锁定,释放时将传入的QMutex解锁)

三、QMutex使用和QMutexLocker使用

1.QMutex的使用

void CThread::run()
{
        //互斥锁锁定
        m_mutex->lock();
        //输出当前线程的线程ID
        qDebug() << QThread::currentThreadId();
        //互斥锁解锁
        m_mutex->unlock();
}

2.QMutexLocker的使用

void CThread::run()
{
        //创建QMutexLocker的局部变量,并将类中互斥锁指针传入(此处互斥锁被locker锁定)
        QMutexLocker locker(m_mutex);
        qDebug() << QThread::currentThreadId();
        //当locker作用域结束locker将互斥锁解锁
}

通过1、2的代码比较,我们会发现QMutexLocker的代码中没有手动调用锁定和解锁,由此可看出MutexLocker简化了互斥锁的锁定和解锁。

四、检验QMutexLocker是否将传入的互斥锁锁定

1.操作解释

使用两种实现方法完全不同线程测试
两个线程使用同一个互斥锁
一个线程使用QMutexLocker一个线程单纯使用QMutex

2.CMoveFuncClass(使用moveToThread实现,使用QMutexLocker)

CMoveFuncClass.h

#ifndef CMOVEFUNCCLASS_H
#define CMOVEFUNCCLASS_H

#include <QObject>
#include <QMutex>

class CMoveFuncClass : public QObject
{
    Q_OBJECT
public:
    explicit CMoveFuncClass(QObject *parent = nullptr);
    ~CMoveFuncClass();

    void setMutex(QMutex *mutex);

public slots:
    void doSomething();

private:
    QMutex * m_mutex;   //定义一个互斥锁变量
};

#endif // CMOVEFUNCCLASS_H

CMoveFuncClass.cpp

#include "CMoveFuncClass.h"

#include <QDebug>
#include <QThread>

CMoveFuncClass::CMoveFuncClass(QObject *parent)
    : QObject(parent)
{
}

CMoveFuncClass::~CMoveFuncClass()
{
}

void CMoveFuncClass::doSomething()
{
    //创建QMutexLocker的局部变量,并将类中互斥锁指针传入(此处互斥锁被locker锁定)
    QMutexLocker locker(m_mutex);

    qDebug() << "我的实现方法为moveToThread" <<"开始3秒睡眠" << "使用QMutexLocker";
    qDebug() << "线程ID:" << QThread::currentThreadId();
    QThread::sleep(3);  //设置线程睡眠3秒(单位为秒)
    qDebug() << "我的实现方法为moveToThread" <<"线程运行完成,结束睡眠\n\n";

    //当locker作用域结束locker将互斥锁解锁
}

void CMoveFuncClass::setMutex(QMutex *mutex)
{
    m_mutex = mutex;
}

3.CThread类(继承QThread实现,单纯使用QMutex)

CThread.h

#ifndef CTHREAD_H
#define CTHREAD_H

#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>

class CThread : public QThread
{
    Q_OBJECT
public:
    explicit CThread(QObject *parent = nullptr);
    ~CThread();

    void run();

    void setMutex(QMutex *mutex);

private:
    QMutex *            m_mutex;            //定义一个线程锁变量

};

#endif // CTHREAD_H

CThread.cpp

#include "CThread.h"
#include <QDebug>

CThread::CThread(QObject *parent)
    : QThread(parent)
{
}

CThread::~CThread()
{
}

void CThread::run()
{
    //互斥锁上锁
    m_mutex->lock();

    qDebug() << "我的实现方法为继承QThread" << "开始3秒睡眠" << "单纯使用QMutex";
    qDebug() << "线程ID:" << QThread::currentThreadId();
    QThread::sleep(3);  //设置线程睡眠3秒(单位为秒)
    qDebug() << "我的实现方法为继承QThread" <<"线程运行完成,结束睡眠";

    //互斥锁解锁
    m_mutex->unlock();
}

void CThread::setMutex(QMutex *mutex)
{
    m_mutex = mutex;
}

4.CMainWindow调用类

CMainWindow.h

#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H

#include <QMainWindow>
#include "CThread.h"
#include "CMoveFuncClass.h"

namespace Ui {
class CMainWindow;
}

class CMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit CMainWindow(QWidget *parent = 0);
    ~CMainWindow();

signals:
    void startMoveThread();

private slots:
    void on_startBtn_clicked();		//触发方法二函数的信号

private:
    Ui::CMainWindow *ui;

    CThread         *m_cThread;		//方法一指针

    CMoveFuncClass  *m_moveFunc;	//方法二指针

    QThread         *m_thread;		//方法二所移至的线程指针

    QMutex          *m_mutex;       //两个线程使用的线程锁
};

#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"
#include "ui_CMainWindow.h"

#include <QDebug>

CMainWindow::CMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CMainWindow)
{
    ui->setupUi(this);

    /方法一///
    //new出CThread对象
    m_cThread = new CThread;


    /方法二///
    //new一个moveToThread的接收线程并启动
    m_thread = new QThread;
    //new出CMoveFuncClass对象
    m_thread->start();  //一定记得启动,否则运行不了
    m_moveFunc = new CMoveFuncClass;
    //连接相应信号槽
    connect(this, &CMainWindow::startMoveThread, m_moveFunc, &CMoveFuncClass::doSomething);
    connect(m_thread, &QThread::finished, m_moveFunc, &QObject::deleteLater);
    //将对象移至线程
    m_moveFunc->moveToThread(m_thread);

	//创建线程共用的互斥锁
    m_mutex = new QMutex;
    //下方为m_mutex的地方更改为new QMutex,则能实现第一节,第二张图的效果
    m_cThread->setMutex(m_mutex);
    m_moveFunc->setMutex(m_mutex);
}

CMainWindow::~CMainWindow()
{
    delete m_mutex;

    delete m_moveFunc;
    m_thread->exit();
    m_thread->wait(1);
    delete m_thread;

    m_cThread->exit();
    m_cThread->wait(1);
    delete m_cThread;
    delete ui;
}

void CMainWindow::on_startBtn_clicked()
{
    //通过start启动方法一线程
    m_cThread->start();
    //发送信号启动方法二线程
    emit startMoveThread();
}

运行上方的代码(第一节,第一张效果图)可看出,使用QMutexLocker的线程首先运行,且代码中无锁定和解锁的操作,但另外一个线程依然等该线程运行完成后运行,由此可看出,使用QMutexLocker是实现了互斥锁的锁定和解锁的。

总结

QMutexLocker提供的简化互斥锁锁定和解锁的机制在很多时候时蛮方便的,在使用互斥锁的地方使用QMutexLocker会减去许多安全隐患;不过在多线程循环输出ABC的时候好像就不适合该方法。所以使用类似的类还得按情况而定

相关文章

启动QThread线程的两种方法(含源码+注释)
Qt互斥锁(QMutex)、条件变量(QWaitCondition)讲解+QMutex实现多线程循环输出ABC(含源码+注释)
QSemaphore的使用+QSemaphore实现循环输出ABC(含源码+注释)
QRunnable线程、QThreadPool(线程池)的使用(含源码+注释)
Qt读写锁(QReadWriteLock)的使用、读写锁的验证(含源码+注释)
Qt读写锁(QWriteLocker、QReadLocker)的理解和使用(含部分源码)
Qt之线程运行指定函数(含源码+注释,优化速率)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 o/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/978750.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

异常c/c++

目录 1.c语言传统处理错误方式 1、终止程序 2、返回错误码 2.c异常概念 3.异常的使用 3.1异常的抛出与捕获 3.2异常安全&#xff08;还有一些异常重新抛出&#xff09; 3.3异常规范 4.自定义异常体系 5.c标准库的异常体系 6.异常优缺点 1、优点 2、缺点 7、补充 1.…

SAP-ABAP:使用ST05(SQL Trace)追踪结构字段来源的步骤

ST05 是 SAP 提供的 SQL 跟踪工具&#xff0c;可以记录程序运行期间所有数据库操作&#xff08;如 SELECT、UPDATE、INSERT&#xff09;。通过分析跟踪结果&#xff0c;可以精准定位程序中结构字段对应的数据库表。 步骤1&#xff1a;激活ST05跟踪 事务码 ST05 → 点击 Activa…

sklearn中的决策树-分类树:剪枝参数

剪枝参数 在不加限制的情况下&#xff0c;一棵决策树会生长到衡量不纯度的指标最优&#xff0c;或者没有更多的特征可用为止。这样的决策树 往往会过拟合。为了让决策树有更好的泛化性&#xff0c;我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大&#xff0c;正确的剪枝策…

安宝特科技 | Vuzix Z100智能眼镜+AugmentOS:重新定义AI可穿戴设备的未来——从操作系统到硬件生态,如何掀起无感智能革命?

一、AugmentOS&#xff1a;AI可穿戴的“操作系统革命” 2025年2月3日&#xff0c;Vuzix与AI人机交互团队Mentra联合推出的AugmentOS&#xff0c;被业内视为智能眼镜领域的“iOS时刻”。这款全球首个专为智能眼镜设计的通用操作系统&#xff0c;通过三大突破重新定义了AI可穿戴…

基于Rook的Ceph云原生存储部署与实践指南(上)

#作者&#xff1a;任少近 文章目录 1 Ceph环境准备2 rook部署ceph群集2.1 Rook 帮助地址2.2 安装ceph2.3 获取csi镜像2.4 Master参加到osd2.5 设置默认存储 3 Rook部署云原生RBD块存储3.1 部署storageclass资源3.2 部署WordPress使用RBD3.3 WordPress访问 4 Rook部署云原生RGW…

2月27(信息差)

&#x1f30d;雷军超钟睒睒登顶中国首富 身家近4400亿元 &#x1f384;全球AI大混战升温&#xff01;超越Sora的阿里万相大模型开源 家用显卡都能跑 ✨小米15 Ultra、小米SU7 Ultra定档2月27日 雷军宣布&#xff1a;向超高端进发 1.刚刚&#xff01;DeepSeek硬核发布&#xff…

【Linux】文件系统深度解析:从基础到高级应用

&#x1f3ac; 个人主页&#xff1a;努力可抵万难 &#x1f4d6; 个人专栏&#xff1a;《C语法》《Linux系列》《数据结构及算法》 ⛰️ 路虽远&#xff0c;行则将至 目录 &#x1f4da;一、引言&#xff1a;文件系统的核心作用与历史演进 &#x1f4d6;1.文件系统的定义与功…

《Effective Objective-C》阅读笔记(中)

目录 接口与API设计 用前缀避免命名空间冲突 提供“全能初始化方法” 实现description方法 尽量使用不可变对象 使用清晰而协调的命名方式 方法命名 ​编辑类与协议命名 为私有方法名加前缀 理解OC错误模型 理解NSCopying协议 协议与分类 通过委托与数据源协议进行…

MongoDB—(一主、一从、一仲裁)副本集搭建

MongoDB集群介绍&#xff1a; MongoDB 副本集是由多个MongoDB实例组成的集群&#xff0c;其中包含一个主节点&#xff08;Primary&#xff09;和多个从节点&#xff08;Secondary&#xff09;&#xff0c;用于提供数据冗余和高可用性。以下是搭建 MongoDB 副本集的详细步骤&am…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.3.1单节点安装(Docker与手动部署)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 10分钟快速部署Elasticsearch单节点环境1. 系统环境要求1.1 硬件配置推荐1.2 软件依赖 2. Docker部署方案2.1 部署流程2.2 参数说明2.3 性能优化建议 3. 手动部署方案3.1 安…

Rt-thread源码剖析(1)——内核对象

前言 该系列基于rtthread-nano的内核源码&#xff0c;来研究RTOS的底层逻辑&#xff0c;本文介绍RTT的内核对象&#xff0c;对于其他RTOS来说也可供参考&#xff0c;万变不离其宗&#xff0c;大家都是互相借鉴&#xff0c;实现不会差太多。 内核对象容器 首先要明确的一点是什…

html css js网页制作成品——HTML+CSS甜品店网页设计(5页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…

Trae根据原型设计稿生成微信小程序密码输入框的踩坑记录

一、需求描述 最近经常使用Trae生成一些小组件和功能代码&#xff08;对Trae赶兴趣的可以看之前的文章《TraeAi上手体验》&#xff09;&#xff0c;刚好在用uniapp开发微信小程序时需要开发一个输入密码的弹框组件&#xff0c;于是想用Trae来实现。原型设计稿如下&#xff1a;…

斩波放大器

目录 简介 自稳零斩波放大器 噪声 简介 双极性放大器的失调电压为25 μV&#xff0c;漂移为0.1 μV/C。斩波放大器尽管存在一些不利影 响&#xff0c;但可提供低于5 μV的失调电压&#xff0c;而且不会出现明显的失调漂移&#xff0c; 以下图1给出了基本的斩波放大器电路图。…

windows设置暂停更新时长

windows设置暂停更新时长 win11与win10修改注册表操作一致 &#xff0c;系统界面不同 1.打开注册表 2.在以下路径 \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 右键新建 DWORD 32位值&#xff0c;名称为FlightSettingsMaxPauseDays 根据需求填写数…

DIALOGPT:大规模生成式预训练用于对话响应生成

摘要 我们提出了一个大规模、可调节的神经对话响应生成模型&#xff0c;DIALOGPT&#xff08;对话生成预训练变换器&#xff09;。该模型训练于从2005年至2017年间Reddit评论链中提取的1.47亿次类似对话的交流&#xff0c;DIALOGPT扩展了Hugging Face的PyTorch变换器&#xff…

Mac端不显示正常用户名,变成192的解决方法

今天打开终端&#xff0c;本应该显示机器名的&#xff0c;但是此时显示了192。 问题原因&#xff1a; 当路由器的DNS使用默认的 192.168.1.1 或 192.168.0.1 的时候 Terminal 里的计算机名 会变成 localhost。当路由器的DNS使用自定义的 例如 运营商的DNS 或者 公共DNS的时候 …

SD 卡无屏安装启动树莓派5

最近想用一下树莓派5&#xff0c;拿出来一看&#xff0c;是 Micro-HMDI 的接口&#xff0c;手头正好没有这个接口线&#xff0c;便研究如何在没有显示屏的情况下&#xff0c;安装启动树莓派。 一、使用 Raspberry Pi Imager 烧录 SD 卡 选择 Raspberry Pi Imager 来烧录 SD 卡…

Xlua 编译 Windows、UWP、Android、iOS 平台支持库

Xlua 编译 Windows、UWP、Android、iOS 平台支持库 Windows&#xff1a; 安装 Visual Studio&#xff08;推荐 2017 或更高版本&#xff09; 安装 CMake&#xff08;https://cmake.org/&#xff09; macOS&#xff1a; 安装 Xcode 和命令行工具 安装 CMake 检查 cmake 是否安…

npm : 无法加载文件 E:\ProgramFiles\Nodejs\npm.ps1,因为在此系统上禁止运行脚本。

这个错误是因为 Windows 系统的 PowerShell 执行策略 限制了脚本的运行。默认情况下&#xff0c;PowerShell 的执行策略是 Restricted&#xff0c;即禁止运行任何脚本。以下是解决该问题的步骤&#xff1a; 1. 检查当前执行策略 打开 PowerShell&#xff08;管理员权限&#x…