C++ 并发编程:深入理解 std::mutex 和 std::lock_guard

C++并发编程:互斥锁std::mutex和lock_guard的使用 对象离开其作用域时,会自动调用析构函数,该析构函数会释放锁。这确保了在任何情况下(包括由于异常等原因导致的提前退出),锁都会被正确释放,从而避免了忘记手动释放锁而导致的死锁问题。mutex 用于控制多个线程访问共享资源,确保在任意时刻只有一个线程可以访问该资源,避免数据竞争。这确保了同一时刻只有一个线程可以访问被保护的资源,从而防止多线程并发访问导致的数据不一致性。是 C++ 标准库中提供的一个模板类,用于在其构造时自动获取锁,在析构时自动释放锁。是 C++ 标准库中提供的一种用于多线程同步的互斥锁实现。 阅读详情
AI摘要

本文深入探讨C++并发编程中std::mutex和std::lock_guard的使用。介绍了互斥锁解决多线程访问共享资源时的数据竞争问题,阐述了std::mutex基本用法及手动锁痛点,讲解了std::lock_guard自动锁管理、底层原理、应用场景,还给出注意事项和锁类型选择建议。

在这里插入图片描述

C++ 并发编程:深入理解 std::mutex 和 std::lock_guard

一、为什么需要互斥锁?

在多线程程序中,当多个线程同时访问共享资源时,可能会引发数据竞争(Data Race)问题。比如两个线程同时修改同一个全局变量:

int counter = 0; // 共享资源

void increment() {
    for (int i = 0; i < 100000; ++i) {
        counter++; // 非原子操作
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join(); t2.join();
    std::cout << "Final counter: " << counter; // 可能输出小于200000

运行结果可能是不可预测的,因为 counter++ 不是原子操作。此时需要互斥锁(Mutex)来保证操作的原子性。


二、std::mutex 基本用法

std::mutex 是 C++11 提供的互斥锁类,通过 lock() 和 unlock() 方法手动控制锁。

修正后的线程安全代码:

include <mutex>

std::mutex mtx;
int counter = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        mtx.lock();
        counter++;
        mtx.unlock(); // 必须显式解锁
}
// 最终输出一定是200000

手动锁的痛点:

  • 忘记解锁会导致死锁。
  • 异常发生时可能跳过解锁步骤。

三、std::lock_guard:自动锁管理

std::lock_guard 是一个 RAII 包装类,构造时自动加锁,析构时自动解锁,确保异常安全。

使用示例:

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 自动加锁
        counter++;
        // 离开作用域时自动解锁
}

核心特性:

  1. 自动管理生命周期:无需手动调用 unlock()。
  2. 异常安全:即使代码抛出异常,锁也会被释放。
  3. 不可复制:确保锁的所有权唯一。

四、lock_guard 的底层原理

简化实现代码:

template <typename Mutex>
class lock_guard {
public:
    explicit lock_guard(Mutex& m) : mutex(m) {
        mutex.lock(); // 构造时加锁
~lock_guard() {

        mutex.unlock(); // 析构时解锁
// 禁止复制

    lock_guard(const lock_guard&) = delete;
    lock_guard& operator=(const lock_guard&) = delete;

private:
    Mutex& mutex;
};

五、实际应用场景

案例1:线程安全的银行账户

class BankAccount {
private:
    std::mutex mtx;
    double balance;
public:
    void deposit(double amount) {
        std::lock_guard<std::mutex> lock(mtx);
        balance += amount;
void withdraw(double amount) {

        std::lock_guard<std::mutex> lock(mtx);
        if (balance >= amount) {
            balance -= amount;
}

};

案例2:保护文件写入

std::mutex log_mutex;

void write_log(const std::string& message) {
    std::lock_guard<std::mutex> lock(log_mutex);
    std::ofstream file("app.log", std::ios::app);
    file << message << std::endl;
    // 文件流和锁都会自动释放

六、注意事项

  1. 锁的粒度:
// 错误:锁范围过大,影响性能
std::lock_guard<std::mutex> lock(mtx);
{
       data1.process();
       data2.process(); // 这两个操作可能不需要共享锁
}
// 正确:细化锁范围
{
	   std::lock_guard<std::mutex> lock1(mtx1);
       data1.process();
}
{
       std::lock_guard<std::mutex> lock2(mtx2);
       data2.process();
}

  1. 避免嵌套死锁:
std::mutex mtx;

   void foo() {
       std::lock_guard<std::mutex> lock(mtx);
       bar(); // 如果bar()也申请同一个锁,导致死锁
}
void bar() {

       std::lock_guard<std::mutex> lock(mtx); // 死锁!
}

  1. 配合其他锁类型:
  • std::unique_lock:更灵活(延迟锁定、转移所有权)。
  • std::shared_mutex:读写分离锁(C++17)。

七、常见问题解答

Q1:lock_guard 和 unique_lock 有什么区别?

特性lock_guardunique_lock
锁策略必须立即锁定可延迟锁定 (defer_lock)
所有权转移不支持支持
性能更高(无额外开销)稍低(更多功能)
适用场景简单作用域锁定需要灵活控制锁的情况

Q2:如何选择锁的类型?

  • 简单场景用 lock_guard(90% 的情况)。
  • 需要条件变量或延迟锁定用 unique_lock。

八、总结

  • std::mutex:基础互斥锁,需手动管理锁生命周期。
  • std::lock_guard:
    • 自动管理锁,确保异常安全。
    • 适用于简单的作用域锁定。
    • 代码更简洁,避免忘记解锁。

最佳实践:

{
	std::lock_guard<std::mutex> lock(mtx); // 进入作用域加锁
	// 操作共享资源...
}	// 离开作用域自动解锁

参考

【1】C++学习随笔——lock_guard和mutex的使用方法
【2】std::lock_guard

【C++】锁卫士(lock_guard) 通过学习和掌握 C++ 中的 lock_guard,可以更加方便地管理互斥锁,确保共享资源的安全访问,并提高代码的可读性和可维护性。 阅读详情

相关推荐

C++多线程编程:深入理解std::mutex互斥锁原理与实战应用

在多线程编程中,数据竞争是导致程序崩溃、结果错误的常见根源,其本质是多个线程对同一共享资源的无序访问。为了解决这一问题,互斥锁作为一种核心的同步机制应运而生,它通过确保临界区代码的互斥执行,为共享数据提供原子性访问保护。从技术价值看,互斥锁不仅避免了数据不一致,还通过内存屏障保证了修改的可见性,是现代并发编程的基石。在C++中,std::mutex及其衍生类型(如递归锁、定时锁、读写锁)为不同应用场景提供了标准化解决方案,结合RAII思想的lock_guard和unique_lock,能有效防止资源泄漏。本

weixin_34110749的博客 563

C++并发 互斥

C++多线程 mutex

搬砖 2631

C++多线程编程:深入理解std::mutex与std::lock_guard的实战应用

在多线程编程中,数据竞争是导致程序行为不确定和难以调试的常见问题。其核心原理在于多个线程未同步地并发访问同一共享资源,导致读写冲突。为解决此问题,互斥锁作为一种基础同步原语被引入,它通过确保临界区代码的排他执行来保障线程安全。在C++工程实践中,std::mutex提供了底层的锁机制,而std::lock_guard则基于RAII(资源获取即初始化)思想,将锁的生命周期与对象作用域绑定,实现了异常安全的自动资源管理。这种组合极大地简化了锁的使用,避免了因忘记解锁或异常抛出导致的死锁风险,是构建健壮并发程序如

weixin_33508411的博客 264

std::mutex和std::lock_guard

互斥锁是一种可锁定的对象,它被设计用来在关键代码段需要独占访问时发出信号,防止具有相同保护的其他线程并发执行并访问相同的内存位置。互斥对象提供独占性,不支持递归性(也就是说,一个线程不应该锁定它已经拥有的互斥对象,否则会导致死锁)。 构造函数:仅支持默认构造函数,不支持拷贝和移动构造函数。完成构造后,处于unlock状态。互斥锁的构造本身不是原子的:在构造时访问对象可能会引发数据竞争。 lock():调用线程锁住互斥对象,必要时阻塞,互斥对象被作为原子操作访问/修改(不会导致数据竞争)。 ...

weixin_41440739的博客 9709

C++多线程编程:深入理解std::mutex与std::lock_guard的RAII锁管理

在多线程编程中,数据竞争是导致程序行为不确定和结果错误的常见根源。其核心原理在于多个线程对共享资源的非原子性访问,破坏了数据的一致性。为了解决这一问题,互斥锁作为一种基础的线程同步原语应运而生,它通过确保临界区代码的互斥执行来保障线程安全。在C++工程实践中,手动管理锁的获取与释放极易因异常或逻辑分支导致死锁或资源泄漏。因此,C++11标准库引入了基于RAII(资源获取即初始化)设计思想的`std::lock_guard`,它能够将锁的生命周期与对象作用域自动绑定,构造时加锁,析构时解锁,从而极大地提升了代

weixin_31236101的博客 244

C++ lock_guard和mutex的使用方法

std::mutex和是 C++ 标准库中用于多线程同步的工具,主要用于防止多个线程同时访问共享资源,导致数据竞争问题。std::mutex是一个用于互斥锁的类,提供了锁定(lock)和解锁(unlock)的功能。

专注基础架构领域 576

C++11开始的多线程编程

时间点类型:chrono::steady_clock::time_point 等(一种是CPU计数器,一种是OS提供的,通常精度高选择steady_clock )时间段类型:chrono::milliseconds,chrono::seconds,chrono::minutes 等。利用 C++ 强类型的特点,明确区分时间点与时间段,明确区分不同的时间单位。方便的运算符重载:时间点+时间段=时间点,时间点-时间点=时间段。时间点例子:2022年1月8日 13点07分10秒。时间段例子:1分30秒。

喜欢打篮球的普通人 2067

C++11多线程(六):std::unique_lock类的用法

unique_lock是个类模板,工作中,一般lock_guard(推荐使用), lock_guard取代了mutex的lock()和unlock(); unique_lock比lock_guard灵活很多,可以手动控mutex解锁,效率率上差一点,内存占用多一点。还是使用上一篇的代码,处理A线程抛异常无法解锁的情况。 下面使用unique_lock来解决,代码...

琅嬛福地 2759

C++并发编程:深入理解std::lock_guard与RAII资源管理

在C++高并发编程中,资源管理是核心挑战之一。RAII(资源获取即初始化)作为一种关键编程范式,通过将资源生命周期与对象生命周期绑定,从根本上解决了资源泄漏问题。其原理是在对象构造时获取资源,在析构时自动释放,确保即使在异常或提前返回等复杂控制流下,资源也能被可靠释放。这一机制为编写异常安全的代码提供了坚实基础,在需要严格配对的资源管理场景中价值尤为突出。std::lock_guard正是RAII思想在线程同步领域的经典应用,它通过自动管理互斥锁的锁定与解锁,简化了多线程编程,避免了因忘记解锁导致的死锁问题

weixin_30824479的博客 436

Claude Code启动失败解决方案,执行文件不兼容一键修复

Claude Code命令行工具突然报错,显示"不支持的16位应用程序"。作者排查Node版本无果后,发现是Anthropic更新导致Windows兼容性问题。解决方法很简单:卸载旧版、切换npm镜像源、重装最新版即可恢复。经验教训:遇到类似问题应先搜索社区反馈,避免无谓排查,同时注意npm源使用后及时还原。整个踩坑过程虽折腾,但最终只是简单的重装问题。

1461

从原理图到PCB:Cadence Allegro 17.4网表同步全流程详解(含第三方网表配置)

本文详细解析了Cadence Allegro 17.4中从Orcad原理图到PCB布局的网表同步全流程。核心内容包括标准的第一方网表同步步骤,以及针对第三方网表导入时关键的封装库路径配置方法,并提供了常见同步错误的排查思路,帮助工程师高效、准确地完成设计数据传递,确保PCB设计顺利开局。

salt9的博客 655

线程纵横:C++并发编程的深度解析与实践

在C++11之前,涉及到多线程问题,都是和平台相关的,比如windows和linux下各有自己的接口,这使得代码的可移植性比较差。C++11中最重要的特性就是对线程进行支持了,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。要使用标准库中的 线程,必须包含< thread >头文件。常见线程函数简介:用于创建和管理的线程对象。通过构造函数启动线程,并将一个可调用对象(如函数、Lambda表达式、函数对象)作为参数传递给线程。返回当前线程的ID。

weixin_73951752的博客 1963

M1/M2 Mac用户看过来:不装VirtualBox,用PD虚拟机也能跑ENSP的保姆级教程

本文为M1/M2 Mac用户提供了一份不依赖VirtualBox,使用Parallels Desktop虚拟机运行ENSP的详细指南。通过ARM架构的Win10镜像选择、组件替代方案和网络配置优化,实现ENSP核心功能的高效运行,特别适合网络工程师在苹果芯片设备上进行网络模拟。

weixin_28683065的博客 413

C++11 多线程同步:mutex、lock_guard、unique_lock 3种锁方案性能对比

本文深入对比了C++11中三种多线程同步方案(mutex、lock_guard、unique_lock)的性能差异与适用场景。通过基准测试数据揭示各方案在单线程与高并发环境下的表现,提供锁粒度优化、死锁预防等实战技巧,帮助开发者根据具体需求选择最佳同步策略,提升多线程程序性能。

weixin_30875157的博客 344

Silvaco Atlas入门指南——从零开始掌握半导体器件仿真

本文为Silvaco Atlas半导体器件仿真软件的入门指南,详细介绍了从零开始掌握该工具的核心流程。内容涵盖Atlas的基本概念、仿真流程、核心文件(输入、结构、输出文件)、交互式与批处理两种操作模式,并逐步演示了如何从定义网格、划分区域、设置电极到进行掺杂、选择物理模型并求解,最终获取和分析器件特性的完整步骤。旨在帮助微电子相关专业人员和工程师快速上手这一强大的“数字实验室”,提升半导体器件设计与研发效率。

weixin_29306317的博客 402

企业级AI项目落地实战指南

企业级 AI 项目落地需构建“分阶段实施 + 多维度风控”的双轮驱动体系:实施端通过 POC 验证技术可行性、试点建立评估标准、规模化实现价值复制,各阶段需结合行业案例(如东阳光药、旺盈集团)提炼可复用经验;风险端则需覆盖技术(数据安全、模型稳定性)、合规(全球监管动态)、组织(人才与文化)维度,通过工具化框架(AI TRISM)与案例策略(邮储银行可解释性设计、拓斯达培训体系)实现风险可控。最终通过“场景聚焦 - 合规嵌入 - 持续优化”的循环机制,实现 AI 技术从“试点成功”到“全面价值创造”的跨越。

2509_93209761的博客 1438

C++多线程编程:深入理解std::mutex互斥锁与死锁预防策略

在多线程编程中,数据竞争是常见的并发问题,它源于多个线程同时访问共享资源。为了解决这一问题,互斥锁(Mutex)作为一种同步原语被引入,其核心原理是通过锁机制确保临界区代码的独占访问,从而维护数据一致性。互斥锁的技术价值在于为并发程序提供了基础的线程安全保障,是实现线程安全数据结构、任务协调等高级并发模式的关键组件。在实际应用场景中,互斥锁广泛用于保护共享变量、文件操作和数据库连接等资源。然而,不当使用互斥锁会引发死锁,即多个线程相互等待对方释放资源而导致的永久阻塞。本文以C++标准库中的std::mute

weixin_33787529的博客 377

喷涂机器人系列编程:ABB IRB 5500_(2).ABB IRB 5500喷涂机器人系统架构与组件

ABB IRB 5500喷涂机器人系统不仅在性能上表现出色,而且在安全和维护方面也提供了全面的解决方案。通过本文的详细介绍,希望读者能够更好地理解和掌握这一系统的架构和功能,为实际应用提供有力支持。

zhubeibei168的博客 779

C++多线程编程:深入理解std::mutex互斥量与死锁防范实战

在多线程编程中,数据竞争是导致程序行为不确定、结果错误甚至崩溃的常见问题。其核心原理在于多个线程对共享资源的非原子性访问,破坏了数据的一致性。为了解决这一问题,互斥量作为一种同步原语应运而生,它通过锁机制确保临界区代码的独占执行,从而保障线程安全。在C++标准库中,std::mutex及其RAII包装器(如std::lock_guard)是实现线程同步的基础工具,对于构建高性能、高可靠的并发系统具有关键价值。然而,不当使用互斥量,尤其是在涉及多个锁的场景下,极易引发死锁,导致线程永久阻塞。本文聚焦于C++并

weixin_33997389的博客 381

【HAL库】STM32CubeMX开发----STM32F407----ETH+LAN8720A+LWIP----ping通

本次实验以芯片为MCU,使用25MHz外部时钟源。以太网PHY层芯片为LAN8720A,由MCU引脚PA8提供时钟。

MQ0522的博客 4844

第11节:GPU 线程层级:线程、线程块、网格

层级标识变量功能线程threadIdx执行单元,处理数据线程块blockIdx管理多个线程,提供共享内存网格管理多个 blockGPU 编程中,合理安排线程层级,是提升性能的关键。

yumeiguo的博客 212

C++并发编程:深入理解lock_guard与unique_lock的差异与应用场景

在多线程编程中,互斥锁是保证数据一致性的核心机制。其原理是通过对共享资源的独占访问,防止多个线程同时修改数据导致竞态条件。RAII(资源获取即初始化)技术将锁的获取与释放绑定到对象生命周期,有效避免了资源泄漏和死锁问题。在C++标准库中,std::lock_guard和std::unique_lock是两种基于RAII思想的锁封装器,它们在设计哲学和性能开销上存在显著差异。std::lock_guard作为轻量级锁,适用于锁域清晰、无需手动干预的场景;而std::unique_lock则提供了更灵活的锁管理

weixin_34168880的博客 384

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

std::mutex加锁失败?lock_guard帮你规避90%的多线程风险

解决C++多线程数据竞争难题,深入解析std::mutex加锁机制与lock_guard的自动管理优势。涵盖互斥锁常见陷阱、RAII原理应用及典型使用场景,有效规避资源泄漏与死锁问题。掌握高效线程同步方法,提升代码安全性,值得收藏。

ProceSeed的博客 469

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C++多线程编程:深入理解互斥锁与std::unique_lock的灵活应用

在多线程编程中,数据竞争是导致程序行为不确定和崩溃的常见问题。互斥锁作为一种核心的同步机制,通过提供对共享资源的独占访问,确保了线程安全。其底层原理通常涉及操作系统调度和硬件原子指令,在锁竞争时会触发线程切换,带来性能开销。为了高效管理锁的生命周期,C++引入了RAII(资源获取即初始化)技术,将资源绑定到对象生命周期以实现自动释放。std::unique_lock作为RAII的灵活实现,不仅支持延迟上锁、提前解锁和尝试锁等高级功能,还能与条件变量无缝配合,优化锁粒度,从而提升并发性能。在实际工程中,合理运

axfcjwkbi259888707的博客 329

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

C++多线程编程:std::mutex与std::recursive_mutex核心区别与实战选择

在多线程编程中,数据竞争是导致程序不稳定的核心问题,互斥锁作为关键的同步原语,通过原子操作和操作系统调度机制,确保临界区资源的独占访问。其技术价值在于为共享数据提供安全保障,避免并发访问引发的未定义行为,广泛应用于高并发服务器、音视频处理等场景。C++标准库提供了std::mutex与std::recursive_mutex两种锁,前者设计简单、性能高效,适用于大多数线性加锁场景;后者通过引用计数支持同一线程重入,解决了递归函数或复杂调用链中的死锁问题,但会引入额外的性能开销和设计复杂度。理解两者的底层原理

aobu0171的博客 396

C++并发编程实战:深入理解`<mutex>`头文件

在多线程编程中,互斥量(Mutex)是最基础的同步机制之一。C++11标准库中的`<mutex>`头文件提供了一系列互斥量类型和相关工具,用于保护共享数据免受并发访问的破坏。本文将深入解析`<mutex>`头文件中的各个组件,帮助开发者正确使用这些同步原语。 ## 互斥量类型概述 `<mutex>`头文件提供了四种主要的互斥量类型: 1. `std::mutex`:基本的互斥量类型 2. `

gitblog_00422的博客 529
上一篇: ZLG USBCANFD python UDS刷写脚本
下一篇: C++ 并发编程入门:std::atomic 原子变量详解
智驾
博客等级 码龄11年 6671粉丝 574原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智驾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值