理解 lock_guard, unique_lock 与 shared_lock 的设计哲学与应用场景

一. lock_guard

lock_guard 比较简单,利用RAII 方式,构造时加锁,析构时解锁

cpp 复制代码
template <class Mutex>
class lock_guard {
    Mutex& mutex_;
public:
    // 构造时加锁
    explicit lock_guard(Mutex& m) : mutex_(m) { mutex_.lock(); }

    // 支持adopt_lock:接管已经加过锁的mutex
    lock_guard(Mutex& m, std::adopt_lock_t) : mutex_(m) { }

    // 析构时解锁
    ~lock_guard() { mutex_.unlock(); }

    // 禁止拷贝(移动操作因存在用户声明的拷贝操作而不会被隐式生成)
    lock_guard(const lock_guard&) = delete;
    lock_guard& operator=(const lock_guard&) = delete;
};

这里的adopt_lock_t,比较简单,顾名思义领养一个孩子,不是你生的(加锁),但领养后需要照顾(解锁)

cpp 复制代码
std::mutex mtx;
int shared_data = 0;

void test() {
    std::lock_guard<std::mutex> lock(mtx);  
    ++shared_data;
}

二.unique_lock

cpp 复制代码
template <class Mutex>
class unique_lock {
    Mutex* mutex_;
    bool owns_;     // 是否持有锁
public:
    // 默认构造:不关联任何mutex
    unique_lock() noexcept : mutex_(nullptr), owns_(false) {}

    // 普通构造:立即加锁(注意owns_先设为false,lock成功后才设true,保证异常安全)
    explicit unique_lock(Mutex& m) : mutex_(&m), owns_(false) {
        mutex_->lock();
        owns_ = true;
    }

    // 延迟加锁:不立即加锁
    unique_lock(Mutex& m, std::defer_lock_t) : mutex_(&m), owns_(false) {}

    // 尝试加锁:非阻塞
    unique_lock(Mutex& m, std::try_to_lock_t)
        : mutex_(&m), owns_(m.try_lock()) {}

    // 接管已加锁的mutex
    unique_lock(Mutex& m, std::adopt_lock_t) : mutex_(&m), owns_(true) {}

    // 支持移动
    unique_lock(unique_lock&& other) noexcept;
    unique_lock& operator=(unique_lock&& other) noexcept;

    // 手动控制
    void lock();
    void unlock();
    bool try_lock();

    // 析构时:如果持有锁,解锁
    ~unique_lock() { if (owns_) mutex_->unlock(); }
};

跟lock_guard比,unique_lock最核心的区别就三个。

**一是能手动unlock/lock。**你可以在锁的生命周期中间释放锁、做一些不需要锁保护的操作、然后再重新加锁。这对控制锁的粒度至关重要,尤其是在锁保护区域内有耗时操作但这个操作本身不需要锁保护的场景下。

二是支持延迟加锁和try_lock。 defer_lock让你先构造unique_lock对象但不立即加锁,等后面你自己决定什么时候调lock()try_to_lock尝试加锁但不阻塞,加不上就返回false让你自己处理。这两个能力lock_guard完全没有。

**三是支持移动语义。**unique_lock可以从一个作用域移动到另一个作用域,锁的所有权跟着走。lock_guard既不能拷贝也不能移动,锁死在创建它的那个作用域。

三.shared_lock

cpp 复制代码
std::shared_mutex rw_mtx;
std::map<std::string, int> cache;

// 读操作:加共享锁,多个读线程可以并发
int read_cache(const std::string& key) {
    std::shared_lock lock(rw_mtx);  // 共享锁(读锁)
    auto it = cache.find(key);
    return it != cache.end() ? it->second : -1;
}

// 写操作:加独占锁,写的时候不允许任何读或写
void write_cache(const std::string& key, int value) {
    std::unique_lock lock(rw_mtx);  // 独占锁(写锁)
    cache[key] = value;
}

与unique_lock的区别

最大的区别是,对于的管理的对象,不会进行独占,其他的线程通过shared_lock也可以共同的管理共享互斥量(shared_mutex);

相关推荐
JieE2121 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2121 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术1 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦1 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
clint4561 天前
C++进阶(1)——前景提要
c++
用户497863050731 天前
(一)小红的数组操作
算法·编程语言
夜悊1 天前
C++代码示例:进制数简单生成工具
c++
怕浪猫1 天前
Electron 系列文章封面图
算法·架构·前端框架
郝学胜_神的一滴1 天前
CMake 021: IF 条件判据详诠
c++·cmake