当前位置: 首页 > news >正文

【C++入门到精通】Lock_guard与Unique_lock C++11 [ C++入门 ]

在这里插入图片描述

阅读导航

  • 引言
  • 一、RAII机制
    • 1. 概念
    • 2. 原理
    • 3. 优点
  • 二、Lock_guard
    • 1. 官方文档
    • 2. 概念
    • 3. 底层类模版
    • 4. 使用示例
  • 三、Unique_lock
    • 1. 官方文档
    • 2. 概念及底层
    • 3. 使用示例
  • 四、总结
  • 温馨提示

引言

在C++11标准中,为了更方便地使用互斥锁(Mutex)来保证多线程程序的安全性,Lock_guard和Unique_lock这两个类也被引入。它们作为RAII(资源获取即初始化)机制的一种实现方式,在多线程编程中起到了重要的作用。Lock_guard和Unique_lock可以帮助程序员自动管理互斥锁的加锁和解锁,避免忘记解锁而导致的死锁等问题。本文将详细介绍Lock_guard和Unique_lock的使用方法和区别,并通过实例展示如何使用它们来实现线程安全的程序

一、RAII机制

1. 概念

RAII(Resource Acquisition Is Initialization)是一种C++编程技术,它通过将资源的获取和释放与对象的生命周期绑定在一起,以确保资源在对象创建时获取,在对象销毁时释放。这种技术利用了C++对象的构造函数和析构函数的调用机制,使得资源的管理变得更加简洁、安全和可靠。

2. 原理

使用RAII的关键在于将资源的获取和释放操作分别放置在对象的构造函数和析构函数中。当对象被创建时,构造函数负责获取资源并进行必要的初始化工作;当对象被销毁时,析构函数负责释放资源并进行清理工作。由于C++保证在对象销毁时析构函数会被自动调用,所以资源的释放也就得到了保证。

3. 优点

RAII技术的优点如下:

  1. 简洁性:通过对象的自动构造和析构,减少了手动管理资源的代码量,使得程序更加简洁易读。
  2. 安全性:确保资源在适当的时候被释放,避免了常见的资源泄漏和错误状态的产生。
  3. 可靠性:无论在何时何地发生异常或提前退出,都能够保证资源的正确释放,提高程序的可靠性。
  4. 可扩展性:通过继承和组合等方式,可以方便地扩展和管理更复杂的资源。

常见的使用RAII技术的例子包括使用智能指针管理动态内存、使用文件对象进行文件操作、使用互斥锁类进行线程同步等。通过合理运用RAII技术,可以有效地提高代码的可维护性、可读性和可靠性,是现代C++编程中的重要技术之一。

二、Lock_guard

1. 官方文档

⭕Lock_guard官方文档

在这里插入图片描述

2. 概念

std::lock_guard是C++标准库中的一个RAII类模板,用于管理互斥锁(std::mutex)的加锁和解锁操作。它提供了一种简单且安全的方式来确保在退出作用域时互斥锁会被正确地释放,从而避免了忘记解锁而导致的死锁和资源泄漏等问题

3. 底层类模版

// lock_guard类模板,用于管理互斥锁的加锁和解锁操作
template<class _Mutex>
class lock_guard
{
public:// 构造函数,在创建lock_guard对象时自动上锁互斥锁_Mtxexplicit lock_guard(_Mutex& _Mtx): _MyMutex(_Mtx){_MyMutex.lock(); // 使用互斥锁的lock()成员函数进行上锁操作}// 构造函数,在已经上锁的情况下创建lock_guard对象// 在这种情况下,不需要再次上锁互斥锁,因此该构造函数空实现lock_guard(_Mutex& _Mtx, adopt_lock_t): _MyMutex(_Mtx){}// 析构函数,在lock_guard对象销毁时自动解锁互斥锁_Mtx// 使用互斥锁的unlock()成员函数进行解锁操作~lock_guard() _NOEXCEPT{_MyMutex.unlock();}// 禁用拷贝构造函数和拷贝赋值运算符,确保lock_guard对象不可拷贝lock_guard(const lock_guard&) = delete;lock_guard& operator=(const lock_guard&) = delete;private:_Mutex& _MyMutex; // 引用类型成员变量,用于保存互斥锁的引用
};

lock_guard类有以下几个重要成员函数:

  1. explicit lock_guard(_Mutex& _Mtx):该构造函数会在创建lock_guard对象时自动上锁互斥锁_Mtx。它使用互斥锁的lock()成员函数进行上锁操作。
  2. lock_guard(_Mutex& _Mtx, adopt_lock_t):该构造函数用于在已经上锁的情况下创建lock_guard对象。在这种情况下,不需要再次上锁互斥锁,因此该构造函数空实现。
  3. ~lock_guard() _NOEXCEPT:析构函数会在lock_guard对象销毁时自动解锁互斥锁_Mtx。它使用互斥锁的unlock()成员函数进行解锁操作。
  4. lock_guard(const lock_guard&) = deletelock_guard& operator=(const lock_guard&) = delete:禁用拷贝构造函数和拷贝赋值运算符,确保lock_guard对象不可拷贝。

🚨注意lock_guard禁用了拷贝构造函数和拷贝赋值运算符,意味着它不支持拷贝语义,只能通过直接创建对象来使用。这样可以避免多个lock_guard对象同时管理同一个互斥锁而导致的错误行为。

4. 使用示例

使用std::lock_guard非常简单,只需在需要加锁的代码块的开始处创建一个std::lock_guard对象,并将互斥锁作为参数传递给它的构造函数。当代码块结束时,std::lock_guard对象的析构函数会自动调用,从而触发互斥锁的解锁操作。

下面是一个示例代码,展示了如何使用std::lock_guard来管理互斥锁的加锁和解锁:

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;  // 定义一个互斥锁void printMessage(const std::string& message) {std::lock_guard<std::mutex> lock(mtx);  // 创建std::lock_guard对象并传入互斥锁for (int i = 0; i < 5; ++i) {std::cout << message << std::endl;}
}int main() {std::thread t1(printMessage, "Hello");std::thread t2(printMessage, "World");t1.join();t2.join();return 0;
}

在上述示例中,printMessage函数通过创建一个std::lock_guard对象lock,来确保在执行打印操作之前获得互斥锁,并在函数返回时自动释放互斥锁。这样,当多个线程调用printMessage函数时,它们之间的执行将会排他性地进行,避免了数据竞争和输出混乱的问题。

总之,std::lock_guard提供了一种简单且安全的方式来管理互斥锁的加锁和解锁操作,帮助我们在使用互斥锁时避免常见的错误,并提高代码的可靠性和可维护性。

三、Unique_lock

1. 官方文档

⭕Unique_lock官方文档

在这里插入图片描述

2. 概念及底层

unique_lock类模板与lock_guard类似,都是以资源获取就是初始化(Resource Acquisition Is Initialization,缩写为RAII)的方式对锁进行封装。它们都采用了独占所有权的机制,即不能进行拷贝操作。在构造或移动赋值时,需要将一个Mutex对象作为参数传递给unique_lock对象,新创建的unique_lock对象会负责管理该Mutex对象的上锁和解锁操作。

对于使用unique_lock实例化的对象,当对象被创建时,会自动调用构造函数对Mutex对象进行上锁操作,确保当前线程获得互斥访问权限。而当unique_lock对象销毁时,会自动调用析构函数解锁Mutex对象,释放互斥访问权限。通过这种方式,可以方便地避免死锁问题的发生,保证线程安全性。

lock_guard不同的是,unique_lock更加的灵活,提供了更多的成员函数

  1. 上锁/解锁操作locktry_locktry_lock_fortry_lock_untilunlock
  2. 修改操作:移动赋值、交换(swap():与另一个unique_lock对象互换所管理的互斥量所有权)、释放(release():返回它所管理的互斥量对象的指针,并释放所有权)
  3. 获取属性owns_lock(返回当前对象是否上了锁)、operator bool()(与owns_lock()的功能相同)、mutex(返回当前unique_lock所管理的互斥量的指针)。

总的来说unique_lock类模板与lock_guard类似,都提供了一种方便且安全地管理互斥量的方法。它们通过RAII的思想,在对象的生命周期中自动管理锁的上锁和解锁操作,从而简化了编程过程,减少了出错的可能性,并提高了代码的可读性和可维护性。

3. 使用示例

当使用 unique_lock 时,一般需要搭配一个 std::mutex 来进行线程间同步。以下是一个简单的示例:

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx; // 创建一个互斥量void work_in_critical_section() {std::unique_lock<std::mutex> lock(mtx); // 在进入临界区之前,使用 unique_lock 对互斥量进行上锁操作// 在这里执行需要互斥访问的操作std::cout << "Critical section is locked by this thread" << std::endl;
} // 离开作用域时,unique_lock 的析构函数会自动解锁互斥量int main() {std::thread t1(work_in_critical_section);std::thread t2(work_in_critical_section);t1.join();t2.join();return 0;
}

在这个示例中,我们创建了一个互斥量 mtx,然后在 work_in_critical_section 函数中,我们使用 std::unique_lockmtx 进行上锁操作。在 main 函数中,我们创建了两个线程分别执行 work_in_critical_section 函数。由于使用了 unique_lock,它会在离开作用域时自动解锁互斥量,确保线程安全。

四、总结

RAII机制是一种重要的编程范式,Lock_guardUnique_lock是C++标准库中用于资源管理的类模板。它们都基于RAII机制,能够简化资源的管理,提高代码的可读性和可维护性。同时,它们也提供了对互斥量的自动上锁和解锁操作,确保了线程安全。

温馨提示

感谢您对博主文章的关注与支持!另外,我计划在未来的更新中持续探讨与本文相关的内容,会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述

相关文章:

【C++入门到精通】Lock_guard与Unique_lock C++11 [ C++入门 ]

阅读导航 引言一、RAII机制1. 概念2. 原理3. 优点 二、Lock_guard1. 官方文档2. 概念3. 底层类模版4. 使用示例 三、Unique_lock1. 官方文档2. 概念及底层3. 使用示例 四、总结温馨提示 引言 在C11标准中&#xff0c;为了更方便地使用互斥锁&#xff08;Mutex&#xff09;来保…...

电路设计(8)——计时器的multism仿真

1.功能设计 这是一个计时电路&#xff0c;在秒脉冲的驱动下&#xff0c;计时器开始累加&#xff0c;6个数码管分别显示计时的 时&#xff1a;分&#xff1a;秒。 仿真图如下所示&#xff1a; 左边的运放构成了振荡电路&#xff0c;可以产生脉冲波。这个脉冲波给计时电路提供基准…...

Jmeter测试实践:文件下载接口

一 Jmeter步骤 1.打开jmeter4.0&#xff0c;新建测试计划&#xff0c;添加线程组。根据实际情况配置线程属性。 2.添加HTTP请求。根据接口文档进行配置。 Basic部分修改如下&#xff0c;Advanced部分保持默认。这里的参数id是文件的id&#xff0c;我进行了参数化&#xff0c…...

PyQt5实现学生管理系统第三天(下)

目录 一:学生课程导航 二:搜索框 三:查询 四:页面数据展示逻辑 上一节,我们介绍了课程管理的课程查询导航的功能。这一节我们介绍下学生课程的功能实现,因为学生课程只有一个查询列表,内容相对简单,所以我们在这一节也重点讲述下我们页面的展现逻辑。 一:学生课程…...

第4章 | 安徽某高校《统计建模与R软件》期末复习

第4章 参数估计 参数估计是统计建模的关键步骤之一&#xff0c;它涉及根据样本数据推断总体参数的过程。在统计学中&#xff0c;参数通常用于描述总体的特征&#xff0c;如均值、方差等。通过参数估计&#xff0c;我们可以利用样本信息对这些未知参数进行推断&#xff0c;从而…...

localforage本地存储(融合Web Storage,Web SQL Database,ndexedDB三种前端存储)

介绍 localForage 是一个快速而简单的 JavaScript 存储库。通过使用异步存储&#xff08;IndexedDB 或 WebSQL&#xff09;和简单的类 localStorage 的 API &#xff0c;localForage 能改善 Web 应用的离线体验。 在不支持 IndexedDB 或 WebSQL 的浏览器中&#xff0c;localF…...

【JavaWeb学习笔记】17 - ThreadLocal

项目代码 https://github.com/yinhai1114/JavaWeb_LearningCode/tree/main/threadlocal/src/com/yinhai/thread 目录 项目代码 一、什么是ThreadLocal? 二、ThreadLocal快速入门 三、源码解读 一、什么是ThreadLocal? 1. ThreadLocal的作用&#xff0c;可以实现在同一个线…...

【ARMv8M Cortex-M33 系列 1 -- SAU 介绍】

文章目录 Cortex-M33 SAU 介绍SAU 的主要功能包括SAU 寄存器配置示例 Cortex-M33 SAU 介绍 在 ARMv8-M 架构中&#xff0c;SAU&#xff08;Security Attribution Unit&#xff09;是安全属性单元&#xff0c;用于配置和管理内存区域的安全属性。SAU 是 ARM TrustZone 技术的一…...

sklearn 逻辑回归Demo

逻辑回归案例 假设表示 基于上述情况&#xff0c;要使分类器的输出在[0,1]之间&#xff0c;可以采用假设表示的方法。 设 h θ ( x ) g ( θ T x ) h_θ (x)g(θ^T x) hθ​(x)g(θTx)&#xff0c; 其中 g ( z ) 1 ( 1 e − z ) g(z)\frac{1}{(1e^{−z} )} g(z)(1e−z)1​…...

什么是众创空间?他有什么特点?

众创空间&#xff0c;是一种为大众创新创业提供专业化服务的创业服务平台&#xff0c;是顺应网络时代创新创业特点和需求&#xff0c;通过市场化机制、专业化服务和资本化途径构建的低成本、便利化、全要素、开放式的新型创业服务平台的统称。众创空间包括创客空间、联合办公空…...

什么是数据分析思维

参考 一文学会如何做电商数据分析&#xff08;附运营分析指标框架&#xff09; 电子商务该如何做数据分析&#xff1f;如何数据分析入门&#xff08;从各项指标表象进入&#xff09; https://www.processon.com/outline/6589838c3129f1550cc69950 数据分析步骤 什么是数据分析…...

利用Milvus Cloud和LangChain构建机器人:一种引人入胜且通俗易懂的方法

一、引言 机器人已经深入我们的日常生活&#xff0c;从家庭服务到工业生产&#xff0c;再到医疗和运输等领域。然而&#xff0c;这些机器人往往需要复杂的算法和数据处理技术才能有效地执行任务。在这个过程中&#xff0c;人工智能&#xff08;AI&#xff09;和机器学习&#…...

数据结构-如何实现一个队列?逐步解析与代码示例(超详细)

文章目录 前言1.队列的基本概念2.链表与数组实现队列的区别2.1数据存储结构2.2性能2.3内存使用 3.为什么选择链表实现队列&#xff1f;4.结构定义函数声明 5.核心操作5.1初始化 (QInit)5.2销毁 (QDestroy)5.3入队 (QPush)5.4出队 (QPop) 6.队列的查询操作6.1队首元素 (QueueFro…...

爬虫工作量由小到大的思维转变---<第二十三章 Scrapy开始很快,越来越慢(医病篇)>

诊断篇https://blog.csdn.net/m0_56758840/article/details/135170994?ops_request_misc%257B%2522request%255Fid%2522%253A%2522170333243316800180644102%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id1703332433168001806441…...

.Net7.0 或更高版本 System.Drawing.Common 上传图片跨平台方案

项目升级.Net7.0以后&#xff0c;System.Drawing.Common开关已经被删除&#xff0c;且System.Drawing.Common仅在 Windows 上支持 &#xff0c;于是想办法将原来上传图片验证文件名和获取图片扩展名方法替换一下&#xff0c;便开始搜索相关解决方案。 .Net6.0文档&#xff1a;…...

【MySQL】InnoDB和MyISAM区别

文章目录 一、索引不同1 InnoDB聚簇索引&#xff0c;MyISAM非聚簇索引1 InnoDB聚簇索引2 MyISAM非聚簇索引 2 InnoDB必须要有主键&#xff0c;MyISAM允许没有主键3 InnoDB支持外键4 InnoDB不支持全文索引5 索引保存位置不同 二、对事物的支持三、存储结构不同四、存储空间不同五…...

3分钟了解安全数据交换系统有什么用!

企业为了保护核心数据安全&#xff0c;都会采取一些措施&#xff0c;比如做网络隔离划分&#xff0c;分成了不同的安全级别网络&#xff0c;或者安全域&#xff0c;接下来就是需要建设跨网络、跨安全域的安全数据交换系统&#xff0c;将安全保障与数据交换功能有机整合在一起&a…...

记录汇川:MODBUS TCP-梯形图

H5U的MODBUS通信不需要编写程序&#xff0c;通过组态MODBUS通信配置表&#xff0c;实现数据通信。 Modbus-TCP 主站即Modbus-TCP客户端&#xff0c;通过Modbus-TCP配置&#xff0c;可最多支持同时与31个 Modbus-TCP服务器&#xff08;从站&#xff09;进行通讯。 …...

electron + sqlite3 解决打包后无法写入数据库

前言 window环境。 electron28.0.0 sqlite35.1.6 使用 electron-builder 打包。 本文旨在解决打包后无法写入数据库的问题。 但如果你是打包后无法访问sqlite&#xff0c;且有报错弹窗&#xff0c;不妨也看看本文。 也许是同一种原因。 错误原因分析 打包后无法创建db文件&…...

【uniapp小程序-生成二维码+多个图片文字合并一张图】

<!-- 二维码 --><canvas id"qrcode" canvas-id"qrcode" width"120" ></canvas><!-- 生成带小程序码的分享图片 --><canvas canvas-id"shareCanvas" class"share-canvas"></canvas>#qrc…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...