跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++java算法

C++ 多线程并发:资源保护、std::mutex 与 RAII 实践

探讨 C++ 多线程环境下的资源保护机制,重点讲解临界区概念及 std::mutex 的使用。通过对比手动加锁与 RAII 封装的 std::lock_guard,说明异常安全的重要性。文章分析了锁粒度对性能的影响,指出判断与操作需在同一锁内以避免竞态条件,并总结了死锁风险规避原则。同时结合 Java synchronized 关键字进行跨语言对比,强调共享数据必须受保护的核心并发思维。

GitMaster发布于 2026/3/16更新于 2026/8/2451 浏览

一、先问一个工程问题

你有一个共享容器:

std::vector<int> data;

两个线程同时往里面 push_back()。

会发生什么?

你可能会说:

vector 不是自动扩容的吗?

是的,但:

vector 不是线程安全的。

内部会:

  • 修改 size
  • 可能 realloc
  • 移动内存

如果两个线程同时写:

未定义行为。

二、资源保护的本质

并发系统里最重要一句话:

不是'给代码加锁',而是'给资源加保护策略'。

资源 = 被多个线程共享的数据。

三、什么是临界区(Critical Section)

临界区是:

访问共享资源的代码区域。

例如:

data.push_back(1);

这一行,就是临界区。

四、最原始写法(危险)

std::mutex mtx; 
void task() { 
    mtx.lock(); 
    data.push_back(1); 
    mtx.unlock(); 
}

看起来没问题。

但如果中间抛异常?

mtx.lock(); 
throw std::runtime_error("error"); 
mtx.unlock(); // 永远执行不到

锁永远不释放。

其他线程:

永久阻塞(死锁)。

五、C++ 的核心思想:RAII

RAII = Resource Acquisition Is Initialization

意思:

资源的获取与对象生命周期绑定。

锁对象在构造时加锁,在析构时自动解锁。

这就是:

std::lock_guard

六、正确写法:std::lock_guard

std::mutex mtx; 
void task() { 
    std::lock_guard<std::mutex> lock(mtx); 
    data.push_back(1); 
}

作用:

  • 构造 → 自动 lock
  • 离开作用域 → 自动 unlock

无论:

  • return
  • 异常
  • break

都会释放锁。

七、Java 对比:synchronized

Java 写法:

synchronized (lock) { 
    data.add(1); 
}

本质类似:

  • 进入代码块 → 加锁
  • 离开代码块 → 自动释放

区别:

C++Java
lock_guard 是对象synchronized 是语言关键字
手动控制 mutexJVM 管理 monitor

八、完整并发示例(安全版)

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

std::vector<int> data;
std::mutex mtx;

void task() {
    for (int i = 0; i < 10000; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        data.push_back(i);
    }
}

int main() {
    std::thread t1(task);
    std::thread t2(task);
    t1.join();
    t2.join();
    std::cout << data.size() << std::endl;
}

输出:

20000

稳定。

九、锁的粒度问题(工程重点)

你这样写:

void task() {
    std::lock_guard<std::mutex> lock(mtx);
    for (int i = 0; i < 10000; ++i) {
        data.push_back(i);
    }
}

锁范围更大。

优点:

  • 锁竞争少

缺点:

  • 阻塞时间更长
工程原则:

锁只保护'共享资源操作', 不要把耗时操作放在锁里。

十、错误示例:锁太小

if (!data.empty()) {
    std::lock_guard<std::mutex> lock(mtx);
    data.pop_back();
}

问题:

data.empty() 没加锁。

可能:

线程 A 判断非空 线程 B pop 完 线程 A 再 pop → 崩溃

正确写法:

std::lock_guard<std::mutex> lock(mtx);
if (!data.empty()) {
    data.pop_back();
}

十一、资源保护系统思维

写并发代码前问:

  1. 这个数据是否共享?
  2. 是否有写操作?
  3. 锁由谁持有?
  4. 锁范围是否最小化?

十二、死锁风险

死锁发生在:

  • 两个线程
  • 持有不同锁
  • 相互等待

例如:

线程 A:锁 m1 → 锁 m2 线程 B:锁 m2 → 锁 m1

工程规避方式:

统一加锁顺序。

十三、工程 Checklist

✅ 共享数据必须有唯一 mutex ✅ 永远使用 lock_guard(不要手动 lock/unlock) ✅ 判断 + 操作必须在同一锁内 ✅ 锁只保护数据,不保护耗时操作


十四、Java 再类比总结

概念JavaC++
自动释放锁synchronizedlock_guard
手动锁ReentrantLockstd::mutex
异常安全JVM 保证RAII 保证

十五、本篇总结

线程私有栈,共享堆; 共享必保护; RAII 是 C++ 锁的灵魂。

目录

  1. 一、先问一个工程问题
  2. 二、资源保护的本质
  3. 三、什么是临界区(Critical Section)
  4. 四、最原始写法(危险)
  5. 五、C++ 的核心思想:RAII
  6. 六、正确写法:std::lock_guard
  7. 七、Java 对比:synchronized
  8. 八、完整并发示例(安全版)
  9. 九、锁的粒度问题(工程重点)
  10. 工程原则:
  11. 十、错误示例:锁太小
  12. 十一、资源保护系统思维
  13. 十二、死锁风险
  14. 十三、工程 Checklist
  15. 十四、Java 再类比总结
  16. 十五、本篇总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Python ORM 框架:SQLAlchemy 完全指南
  • 基于微信小程序的助农公益平台的设计与实现
  • Java 动态代理详解:JDK 与 CGLIB 实现对比
  • Edge 边栏 Copilot 图标消失的修复方案
  • Pico 4XVR 1.10.13 安装与使用教程
  • React Native 集成开源鸿蒙应用:WebView 桥接与原生模块方案
  • Docker 部署 MoviePilot V2 自动化影视管理平台教程
  • Python 3.12 下载与安装配置指南
  • 统一大型语言模型和知识图谱:研究路线图与未来方向
  • OpenClaw 多 Agent 与多飞书机器人配置
  • Copilot 四大模式详解:Ask、Edit、Agent、Plan 核心区别
  • Trae 结合 Vizro 低代码构建专业数据可视化仪表板方案
  • 前端国际化实战:i18next 与 react-intl 使用指南
  • 前端监控实战:错误、性能与用户行为追踪
  • 九么 1.0.31:AI 辅助 Python 数据处理实战
  • 解决 Spring Boot 项目中 JUnit 版本冲突引发的 NoSuchMethodError 异常
  • 基于 Fast_LIO 架构将局部规划从 Pure Pursuit 迁移至 TEB 算法的实践
  • GitHub Copilot CLI 斜杠命令速查表
  • Python、NumPy、Pandas 与 Matplotlib 版本兼容指南
  • 《Agent Runtime 工程化》第八章 Checkpoint、Resume、Rollback:8.1 checkpoint 保存什么

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online