c++的mutex和lock_guard如何使用 互斥锁保护共享资源【多线程】

发布时间 - 2026-01-01 00:00:00    点击率:
std::mutex 和 std::lock_guard 是 C++ 多线程中安全同步共享资源的核心工具:前者提供手动加锁/解锁接口,后者通过 RAII 自动管理锁的生命周期,确保异常安全。

在多线程 C++ 程序中,std::mutexstd::lock_guard 是最常用、最安全的同步工具之一,用于保护共享资源不被多个线程同时修改,避免数据竞争(data race)和未定义行为。

mutex 用来上锁,lock_guard 自动管理锁的生命周期

std::mutex 是一个底层互斥量对象,提供 lock()unlock() 手动控制接口;但手动管理容易出错(比如忘记 unlock、异常提前退出导致死锁)。std::lock_guard 是 RAII 封装器:构造时自动加锁,析构时自动解锁(哪怕发生异常也会释放),非常可靠。

  • 必须用 std::mutex 对象的引用初始化 lock_guard,不能传值
  • lock_guard 是不可复制的(deleted copy constructor),只能移动或栈上构造

典型用法:保护共享变量或临界区

假设多个线程要累加同一个 int 变量:

std::mutex mtx;
int shared_counter = 0;

void increment() {
    std::lock_guard guard(mtx); // 构造即加锁
    ++shared_counter;                        // 访问共享资源
} // guard 离开作用域,自动调用 ~lock_guard() → 解锁
  • 所有访问 shared_counter 的地方都必须用同一把 mtx 加锁
  • 锁的作用域越小越好,只包裹真正需要保护的代码段
  • 不要跨函数持有锁(比如把 lock_guard 传给另一个函数),会延长临界区,降低并发性

常见错误和注意事项

容易忽略的细节会影响正确性和性能:

  • 全局或静态 mutex 要确保初始化顺序安全;推荐直接定义(C++11 起保证静态局部变量线程安全初始化)
  • 避免嵌套加锁同一 mutex(会导致死锁),如已持锁再调 lock() 是未定义行为;可用 std::recursive_mutex(但通常说明设计有问题)
  • 不要把 lock_guard 声明在 if 分支外却只在分支内使用——它必须在需要保护的代码前构造
  • 若需尝试加锁或带超时,用 std::unique_lock 替代,lock_guard 不支持这些操作

完整可运行示例

启动两个线程并发调用 increment() 10 万次,最终结果应为 200000:

#include 
#include 
#include 
#include 

std::mutex mtx;
int counter = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard guard(mtx);
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join(); t2.join();
    std::cout << "Final counter: " << counter << "\n"; // 输出 200000
}

去掉 lock_guardmtx,结果大概率小于 200000,甚至每次不同——这就是典型的竞态现象。


# 工具  #   # ai  # c++  # 封装  # 接口  # 线程  # 多线程  # copy  # 对象  # constructor  # 加锁  # 死锁  # 多个  # 解锁  # 是一个  # 也会  # 要把  # 这就  # 不支持 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 黑客如何通过漏洞一步步攻陷网站服务器?  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】  JavaScript如何操作视频_媒体API怎么控制播放  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  如何用腾讯建站主机快速创建免费网站?  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Laravel API资源类怎么用_Laravel API Resource数据转换  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  Laravel怎么在Controller之外的地方验证数据  Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】  Laravel如何实现API速率限制?(Rate Limiting教程)  如何在宝塔面板中修改默认建站目录?  公司网站制作价格怎么算,公司办个官网需要多少钱?  浅谈redis在项目中的应用  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  详解jQuery中的事件  Laravel如何使用Sanctum进行API认证?(SPA实战)  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  BootStrap整体框架之基础布局组件  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  网站制作报价单模板图片,小松挖机官方网站报价?  如何快速上传建站程序避免常见错误?  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体  详解jQuery中基本的动画方法  利用 Google AI 进行 YouTube 视频 SEO 描述优化  Python文本处理实践_日志清洗解析【指导】  Laravel Session怎么存储_Laravel Session驱动配置详解  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  EditPlus 正则表达式 实战(3)  Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议  Python结构化数据采集_字段抽取解析【教程】  如何用低价快速搭建高质量网站?  制作旅游网站html,怎样注册旅游网站?  Linux系统命令中screen命令详解  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  Laravel怎么实现观察者模式Observer_Laravel模型事件监听与解耦开发【指南】  高防服务器如何保障网站安全无虞?  怎样使用JSON进行数据交换_它有什么限制  Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)  Laravel如何创建自定义Facades?(详细步骤)