C++ 线程互斥锁 lock_guard的基本用法

 更新时间:2026年01月21日 16:03:18   作者:Howrun777  
std::lock_guard是C++11提供的RAII风格互斥锁封装类,自动管理互斥锁的加锁/解锁,避免忘记解锁和异常导致的锁无法释放等问题,它通过构造时加锁、析构时解锁的机制,简化了多线程编程中的锁管理,本文介绍C++线程互斥锁lock_guard的基本用法,感兴趣的朋友一起看看吧

std::lock_guard是 C++11 标准库提供的RAII 风格的互斥锁封装类,核心目的是自动管理互斥锁的加锁 / 解锁,从根本上避免 “忘记解锁导致死锁”“异常导致锁无法释放” 这类低级且致命的错误。

一、先理解核心:RAII 设计思想

lock_guard的底层是RAII(资源获取即初始化) 机制 —— 简单说:

  • 构造时获取资源lock_guard对象创建时,自动调用互斥锁的lock()方法加锁;
  • 析构时释放资源lock_guard对象销毁时(比如出作用域),自动调用互斥锁的unlock()方法解锁。

这种 “自动性” 是解决多线程锁管理问题的关键,不用再手动记着unlock()

二、lock_guard的基本用法(对比手动加解锁)

先看错误的手动加解锁(容易出问题):

#include <mutex>
std::mutex mtx;
void wrong_func() {
    mtx.lock(); // 手动加锁
    // 临界区操作:修改共享资源
    int a = 10;
    // 忘记解锁 → 死锁!
    // 或如果临界区抛出异常,unlock()永远执行不到 → 死锁!
    // mtx.unlock(); 
}

再看正确的 lock_guard 用法(自动解锁):

#include <mutex>
std::mutex mtx;
void right_func() {
    // 创建lock_guard对象时,自动调用mtx.lock()
    std::lock_guard<std::mutex> lock(mtx);
    // 临界区:安全操作共享资源
    int a = 10;
} // lock_guard对象出作用域,析构时自动调用mtx.unlock()
  // 即使临界区抛出异常,析构函数也会执行 → 必解锁!

三、lock_guard的核心特性

1. 不可拷贝、不可移动

lock_guard被设计为 “只能在当前作用域使用”,禁止拷贝 / 移动,避免锁的管理权被非法转移:

std::lock_guard<std::mutex> lock1(mtx);
// std::lock_guard<std::mutex> lock2 = lock1; // 编译错误:禁止拷贝
// std::lock_guard<std::mutex> lock3(std::move(lock1)); // 编译错误:禁止移动

2. 作用域决定解锁时机

lock_guard的解锁时机完全由作用域控制,你可以通过{}手动限定作用域,精准控制解锁时机:

void func() {
    {
        std::lock_guard<std::mutex> lock(mtx);
        // 短临界区:只保护必要的代码
        shared_data = 100;
    } // 此处提前解锁,不影响后续非临界区代码
    // 非临界区:无需持锁,提升并发效率
    sleep(1); 
}

3. 轻量级、无额外开销

lock_guard是极简封装,没有额外的成员函数(比如unlock()/lock()),运行时几乎无性能损耗,适合简单的临界区保护。

4. 异常安全

这是lock_guard最核心的优势之一:即使临界区抛出异常,C++ 的异常机制会保证局部对象的析构函数执行,从而确保锁被释放:

void func_with_exception() {
    std::lock_guard<std::mutex> lock(mtx);
    // 临界区抛出异常
    throw std::runtime_error("出错了");
    // 无需手动unlock,析构函数会处理
}
int main() {
    try {
        func_with_exception();
    } catch (...) {
        // 捕获异常后,锁已经被释放,其他线程可正常获取
    }
    return 0;
}

四、lock_guardvsunique_lock(选型参考)

lock_guard是 “轻量版” 锁管理,std::unique_lock是 “功能版”,两者的核心区别如下:

特性std::lock_guardstd::unique_lock
自动加解锁✅ 支持✅ 支持
手动解锁(unlock()❌ 不支持✅ 支持
配合条件变量(cv.wait()❌ 不支持✅ 支持
性能极致轻量略重(有额外状态)
适用场景简单临界区保护复杂同步(如条件变量、手动控制解锁)

简单说:

  • 只要是 “加锁后,作用域结束解锁” 的简单场景,优先用lock_guard(轻量、高效);
  • 如果需要手动解锁、配合条件变量(比如cv.wait()需要解锁后阻塞),用unique_lock

五、完整示例:lock_guard 保护共享资源

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx;
int shared_count = 0; // 共享资源
// 线程函数:累加共享变量
void increment(int n) {
    for (int i = 0; i < n; ++i) {
        // lock_guard自动加锁/解锁
        std::lock_guard<std::mutex> lock(mtx);
        shared_count++;
        // 出循环迭代的作用域,自动解锁
    }
}
int main() {
    std::vector<std::thread> threads;
    // 创建10个线程,每个线程累加1000次
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back(increment, 1000);
    }
    // 等待所有线程结束
    for (auto& t : threads) {
        t.join();
    }
    // 正确输出10000,无数据错乱
    std::cout << "最终count值:" << shared_count << std::endl;
    return 0;
}

总结

  1. std::lock_guard是 C++11 的 RAII 锁封装,构造加锁、析构解锁,核心解决 “忘记解锁 / 异常导致锁泄漏” 的问题;
  2. 轻量级、异常安全、不可拷贝,适合简单临界区的线程安全保护;
  3. 解锁时机由作用域决定,可通过{}手动缩小作用域,提升并发效率;
  4. 复杂同步场景(如条件变量)用unique_lock,简单场景优先用lock_guard

到此这篇关于C++ 线程互斥锁 lock_guard的基本用法的文章就介绍到这了,更多相关C++ 线程互斥锁 lock_guard内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C++ string字符串类

    详解C++ string字符串类

    这篇文章主要介绍了C++ string字符串类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • C语言 程序的编译系统解析

    C语言 程序的编译系统解析

    编译程序的基本功能是把源程序(高级语言)翻译成目标程序。但是,作为一个具有实际应用价值的编译系统,除了基本功能之外,还应具备语法检查、调试措施、修改手段、覆盖处理、目标程序优化、不同语言合用以及人-机联系等重要功能
    2022-02-02
  • C++如何切割String对象的方法

    C++如何切割String对象的方法

    C++相较于Java,Python 并没有提供的字符串分割的函数split,因此需要自己进行编写,本文主要介绍了C++如何切割String对象的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Qt编写地图之实现跨平台功能

    Qt编写地图之实现跨平台功能

    这篇文章主要介绍了如何利用Qt编写地图应用时实现跨平台功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-02-02
  • OpenCV实现实时颜色检测的示例

    OpenCV实现实时颜色检测的示例

    本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考价值,感兴趣的可以了解一下
    2025-06-06
  • C++实现LeetCode(7.翻转整数)

    C++实现LeetCode(7.翻转整数)

    这篇文章主要介绍了C++实现LeetCode(7.翻转整数),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++ 容器中map和unordered map区别详解

    C++ 容器中map和unordered map区别详解

    这篇文章主要为大家介绍了C++ 容器中map和unordered map区别示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • C++字符串和数字的去重操作和鞍点的寻找

    C++字符串和数字的去重操作和鞍点的寻找

    大家好,本篇文章主要讲的是C++字符串和数字的去重操作和鞍点的寻找,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • C/C++使用fmt库实现格式化字符串

    C/C++使用fmt库实现格式化字符串

    fmt库是一个高效、易用的C++格式化库,可以帮助我们方便地进行字符串格式化、输出、日志记录等操作,下面我们就来学习一下fmt格式化字符串的具体操作吧
    2023-12-12
  • C++类与对象的重点知识点详细分析

    C++类与对象的重点知识点详细分析

    类和对象是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型;变量就是可以变化的量,存储在内存中—个可以拥有在某个范围内的可变存储区域
    2023-02-02

最新评论