示例
仅供参考学习
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <chrono>
#include <iostream>
#include <vector>
// ============================================
// 1. std::mutex - 基本互斥锁
// ============================================
void basic_mutex_example() {
std::mutex mtx;
int counter = 0;
// 1.1 使用 lock_guard - 最简单的RAII方式
{
std::lock_guard<std::mutex> lock(mtx);
counter++;
// 作用域结束时自动解锁
}
// 1.2 手动加锁解锁(不推荐,容易忘记解锁)
mtx.lock();
counter++;
mtx.unlock();
// 1.3 尝试加锁
if (mtx.try_lock()) {
counter++;
mtx.unlock();
}
}
// ============================================
// 2. std::unique_lock - 灵活控制锁
// ============================================
void unique_lock_example() {
std::mutex mtx;
// 2.1 基本使用(类似lock_guard)
{
std::unique_lock<std::mutex> lock(mtx);
// 临界区代码
} // 自动解锁
// 2.2 延迟加锁
{
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// 此时还没有加锁
// 做一些不需要锁的工作
lock.lock(); // 手动加锁
// 临界区工作
lock.unlock(); // 手动解锁
// 更多不需要锁的工作
lock.lock(); // 再次加锁
// 更多临界区工作
} // 如果持有锁,会自动解锁
// 2.3 尝试加锁
{
std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
if (lock.owns_lock()) {
// 成功获取锁
std::cout << "获取锁成功\n";
} else {
std::cout << "获取锁失败\n";
}
}
// 2.4 超时加锁(需要timed_mutex)
std::timed_mutex timed_mtx;
{
std::unique_lock<std::timed_mutex> lock(timed_mtx, std::defer_lock);
if (lock.try_lock_for(std::chrono::milliseconds(100))) {
std::cout << "在100ms内获取锁成功\n";
} else {
std::cout << "超时,获取锁失败\n";
}
}
// 2.5 移动语义
auto create_lock = []() {
std::unique_lock<std::mutex> lock(mtx);
return lock; // 可以移动返回
};
std::unique_lock<std::mutex> moved_lock = create_lock();
// moved_lock现在持有锁
}
// ============================================
// 3. std::shared_mutex - 读写锁
// ============================================
void shared_mutex_example() {
std::shared_mutex rw_mtx;
std::string shared_data = "初始数据";
// 3.1 读锁 - 多个线程可以同时读
auto reader = [&]() {
std::shared_lock<std::shared_mutex> read_lock(rw_mtx);
std::cout << "读取: " << shared_data << std::endl;
// 可以有多个线程同时执行这里
};
// 3.2 写锁 - 独占访问
auto writer = [&]() {
std::unique_lock<std::shared_mutex> write_lock(rw_mtx);
shared_data = "更新后的数据";
std::cout << "写入完成" << std::endl;
// 只有一个线程可以执行这里,且会阻塞所有读者
};
// 启动多个读线程和一个写线程
std::vector<std::thread> threads;
for (int i = 0; i < 3; ++i) {
threads.emplace_back(reader);
}
threads.emplace_back(writer);
for (auto& t : threads) {
t.join();
}
}
// ============================================
// 4. std::recursive_mutex - 递归互斥锁
// ============================================
void recursive_mutex_example() {
std::recursive_mutex rec_mtx;
int count = 0;
std::function<void(int)> recursive_func = [&](int n) {
std::lock_guard<std::recursive_mutex> lock(rec_mtx);
count++;
std::cout << "递归层级: " << n << ", count: " << count << std::endl;
if (n > 0) {
recursive_func(n - 1); // 同一线程可以多次获取锁
}
};
recursive_func(3);
}
// ============================================
// 5. std::timed_mutex - 超时互斥锁
// ============================================
void timed_mutex_example() {
std::timed_mutex timed_mtx;
// 5.1 尝试在指定时间内获取锁
if (timed_mtx.try_lock_for(std::chrono::milliseconds(100))) {
std::cout << "在100ms内获取锁成功\n";
// 临界区工作
timed_mtx.unlock();
} else {
std::cout << "超时,获取锁失败\n";
}
// 5.2 尝试在指定时间点前获取锁
auto timeout_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);
if (timed_mtx.try_lock_until(timeout_time)) {
std::cout << "在指定时间点前获取锁成功\n";
timed_mtx.unlock();
} else {
std::cout << "超时,获取锁失败\n";
}
}
// ============================================
// 6. 多锁管理 - 避免死锁
// ============================================
void multi_lock_example() {
std::mutex mtx1, mtx2;
// 6.1 std::lock - 同时锁定多个互斥锁,避免死锁
{
std::lock(mtx1, mtx2); // 原子性地锁定两个互斥锁
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
// 临界区代码
}
// 6.2 std::scoped_lock (C++17) - 更简单的多锁管理
{
std::scoped_lock lock(mtx1, mtx2); // 自动管理多个锁
// 临界区代码
}
}
// ============================================
// 7. 条件变量配合使用
// ============================================
void condition_variable_example() {
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
// 等待线程
auto waiter = [&]() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [&] { return ready; }); // 等待条件满足
std::cout << "条件满足,继续执行\n";
};
// 通知线程
auto notifier = [&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 通知等待的线程
};
std::thread t1(waiter);
std::thread t2(notifier);
t1.join();
t2.join();
}
// ============================================
// 8. 实际应用示例 - 线程安全的计数器
// ============================================
class ThreadSafeCounter {
private:
mutable std::mutex mtx_;
int count_ = 0;
public:
void increment() {
std::lock_guard<std::mutex> lock(mtx_);
++count_;
}
void decrement() {
std::lock_guard<std::mutex> lock(mtx_);
--count_;
}
int get() const {
std::lock_guard<std::mutex> lock(mtx_);
return count_;
}
// 复杂操作示例
void add_if_positive(int value) {
std::unique_lock<std::mutex> lock(mtx_);
if (count_ > 0) {
count_ += value;
}
}
};
// ============================================
// 9. 性能考虑和最佳实践
// ============================================
void performance_tips() {
std::mutex mtx;
// ✅ 好的做法:尽量缩小临界区
{
int temp_result = 0;
// 在锁外做复杂计算
for (int i = 0; i < 1000; ++i) {
temp_result += i * i;
}
std::lock_guard<std::mutex> lock(mtx);
// 只在必要时持有锁
// shared_data = temp_result;
}
// ❌ 不好的做法:在临界区内做复杂计算
{
std::lock_guard<std::mutex> lock(mtx);
// 不要在锁内做复杂计算
int result = 0;
for (int i = 0; i < 1000; ++i) {
result += i * i;
}
// shared_data = result;
}
}
int main() {
std::cout << "=== C++ 互斥锁使用示例 ===" << std::endl;
basic_mutex_example();
unique_lock_example();
shared_mutex_example();
recursive_mutex_example();
timed_mutex_example();
multi_lock_example();
condition_variable_example();
// 测试线程安全计数器
ThreadSafeCounter counter;
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back([&counter]() {
for (int j = 0; j < 100; ++j) {
counter.increment();
}
});
}
for (auto& t : threads) {
t.join();
}
std::cout << "最终计数: " << counter.get() << std::endl;
return 0;
}
核心概念总结
1. 互斥锁类型
- std::mutex: 基本互斥锁,最常用
- std::recursive_mutex: 递归锁,同一线程可多次获取
- std::timed_mutex: 支持超时的互斥锁
- std::shared_mutex: 读写锁,支持多读者单写者
2. 锁管理器
- std::lock_guard: 最简单的RAII锁,构造时加锁,析构时解锁
- std::unique_lock: 灵活的锁管理器,支持延迟加锁、手动控制等
- std::shared_lock: 用于共享锁(读锁)
- std::scoped_lock: C++17引入,用于管理多个锁
3. 锁标签
- std::defer_lock: 延迟加锁
- std::try_to_lock: 尝试加锁
- std::adopt_lock: 接管已经持有的锁
4. 最佳实践
- 优先使用 lock_guard - 简单场景的首选
- 需要灵活控制时使用 unique_lock - 如需要手动解锁/加锁
- 读多写少用 shared_mutex - 提高并发性能
- 尽量缩小临界区 - 减少锁持有时间
- 避免死锁 - 使用 std::lock 或 std::scoped_lock 管理多个锁
- 配合条件变量使用 unique_lock - 因为条件变量需要能够释放锁
5. 选择建议
- 简单保护:std::mutex + std::lock_guard
- 需要灵活控制:std::mutex + std::unique_lock
- 读多写少:std::shared_mutex + std::shared_lock/std::unique_lock
- 递归调用:std::recursive_mutex
- 超时需求:std::timed_mutex
这些工具组合使用可以解决绝大多数多线程同步问题。