在C++中,互斥锁(Mutex)是用于线程同步的重要工具,用于保护共享资源,防止多线程同时访问导致的数据竞争(Data Race)问题。
以下是C++中互斥锁的核心用法和示例:
一、基本互斥锁 std::mutex
1. 包含头文件
#include <mutex>
2. 保护共享资源
std::mutex mtx; // 声明互斥锁
int shared_data = 0; // 共享资源void increment() {mtx.lock(); // 加锁++shared_data; // 临界区mtx.unlock(); // 解锁
}
3. 使用 std::lock_guard
自动管理锁
void safe_increment() {std::lock_guard<std::mutex> lock(mtx); // 构造时加锁,析构时解锁++shared_data; // 自动保护临界区
} // 离开作用域时锁自动释放
二、递归互斥锁 std::recursive_mutex
允许同一线程多次加锁,避免死锁:
std::recursive_mutex rmtx;void func1() {std::lock_guard<std::recursive_mutex> lock(rmtx);// 可以在此处再次加锁func2();
}void func2() {std::lock_guard<std::recursive_mutex> lock(rmtx); // 同一线程可重入// ...
}
三、带超时的互斥锁 std::timed_mutex
std::timed_mutex tmtx;void try_lock_with_timeout() {// 尝试加锁,超时则放弃if (tmtx.try_lock_for(std::chrono::milliseconds(100))) {// 加锁成功tmtx.unlock();} else {// 加锁失败}
}
四、读写锁 std::shared_mutex
(C++17)
允许多个线程同时读,但写时独占:
#include <shared_mutex> // C++17std::shared_mutex rw_mutex;
std::string shared_data;// 读操作(共享锁)
void reader() {std::shared_lock<std::shared_mutex> lock(rw_mutex);// 允许多个读者同时访问std::cout << shared_data << std::endl;
}// 写操作(独占锁)
void writer() {std::unique_lock<std::shared_mutex> lock(rw_mutex);// 独占访问shared_data = "new data";
}
五、锁的高级用法
1. 避免死锁:使用 std::lock
同时锁多个互斥锁
std::mutex mtx1, mtx2;void safe_func() {// 原子性地锁多个互斥锁,避免死锁std::lock(mtx1, mtx2);std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// ...
}
2. 延迟加锁 std::defer_lock
std::mutex mtx;void defer_lock_example() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 此时尚未加锁// ...lock.lock(); // 手动加锁// ...
}
六、常见错误与注意事项
-
忘记解锁:
使用std::lock_guard
或std::unique_lock
自动管理锁,避免手动lock/unlock
。 -
锁粒度不当:
- 过大:性能下降(如锁整个函数)。
- 过小:无法保护共享资源。
-
死锁风险:
- 避免嵌套锁。
- 确保所有线程以相同顺序加锁。
-
性能考量:
- 读写锁(
std::shared_mutex
)适合读多写少的场景。 - 无锁编程(Lock-Free)技术在高性能场景中更优。
- 读写锁(
七、示例:线程安全的计数器
#include <mutex>
#include <thread>
#include <iostream>class Counter {
private:int value = 0;std::mutex mtx;public:void increment() {std::lock_guard<std::mutex> lock(mtx);++value;}int get() {std::lock_guard<std::mutex> lock(mtx);return value;}
};int main() {Counter counter;std::thread t1([&]() {for (int i = 0; i < 10000; ++i) {counter.increment();}});std::thread t2([&]() {for (int i = 0; i < 10000; ++i) {counter.increment();}});t1.join();t2.join();std::cout << "Final value: " << counter.get() << std::endl; // 输出:20000return 0;
}
八、C++ 互斥锁类型对比
类型 | 特性 | 适用场景 |
---|---|---|
std::mutex | 基本互斥锁,不可重入 | 简单互斥场景 |
std::recursive_mutex | 可重入锁,允许同一线程多次加锁 | 递归函数或嵌套锁场景 |
std::timed_mutex | 支持超时的互斥锁 | 需要尝试加锁并设置超时的场景 |
std::shared_mutex | 读写锁,允许多读一写 | 读多写少的场景 |
合理选择互斥锁类型能有效提升代码的安全性和性能。