1. C++锁机制基础与核心挑战
在多线程编程中,锁是最基础的同步工具,但也是最容易出问题的部分。C++标准库提供了多种锁类型,每种都有其适用场景和陷阱。先看一个典型场景:两个线程同时修改共享数据,没有同步保护时会导致数据竞争:
cpp复制int shared_data = 0;
void unsafe_increment() {
for(int i=0; i<1000000; ++i) {
++shared_data; // 这里会出现数据竞争
}
}
这个简单的自增操作在多线程环境下会出问题,因为++shared_data实际上包含三个步骤:读取当前值、增加1、写回新值。当多个线程交错执行这些步骤时,部分增量会丢失。
1.1 标准库锁类型对比
C++11起标准库提供了几种主要锁类型:
| 锁类型 | 特性 | 适用场景 |
|---|---|---|
std::mutex |
基本互斥锁,不可递归 | 大多数需要互斥的场景 |
std::recursive_mutex |
可递归锁,同一线程可多次加锁 | 可能递归调用的函数 |
std::timed_mutex |
带超时功能的互斥锁 | 需要避免长时间阻塞的场景 |
std::shared_mutex |
读写锁,支持共享读和独占写 | 读多写少的场景 |
基础用法示例:
cpp复制std::mutex mtx;
void safe_increment() {
for(int i=0; i<1000000; ++i) {
mtx.lock();
++shared_data;
mtx.unlock(); // 容易忘记解锁导致死锁
}
}
这种直接使用lock()/unlock()的方式存在明显问题:如果在lock()和unlock()之间发生异常或提前返回,锁可能永远不会被释放。这就是RAII技术要解决的核心问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. RAII管理锁:安全锁使用的黄金法则
RAII(Resource Acquisition Is Initialization)是C++资源管理的核心理念,其核心思想是将资源生命周期与对象生命周期绑定。对于锁管理,标准库提供了几种RAII包装器:
2.1 std::lock_guard:最基础的RAII锁管理
cpp复制void safe_increment_raii() {
for(int i=0; i<1000000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 构造时加锁
++shared_data;
// 析构时自动解锁
}
}
lock_guard的特点:
- 构造时立即加锁
