理解 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);

相关推荐
Evand J2 小时前
【MATLAB例程介绍】(17)永磁同步电机(PMSM)基于自适应无迹卡尔曼滤波(AUKF)的电流噪声在线估计。测量噪声协方差自适应与转速估计对比仿真
开发语言·matlab·卡尔曼滤波·无迹卡尔曼滤波·pmsm·电机滤波
choumou_M2 小时前
算法_1:由浅入深学习快速排序QuickSort
学习·算法·排序算法
Coder_Shenshen3 小时前
罗克韦尔ACD工程归档离线变量树解析
算法·c#
BaiPeter3 小时前
ZPL文件预览
开发语言·c++
心仪久了会沦陷5 小时前
C语言数据结构入门——树与二叉树详解:概念、堆实现与链式遍历
c语言·数据结构·算法
小此方5 小时前
[算法实战论:动态规划]背包问题概念,01不满背包问题,01满背包问题,背包问题的滚动数组空间优化
算法·动态规划
悠仁さん6 小时前
【C++】哈希表
c++·算法·散列表
地平线开发者6 小时前
点云算法整理与常用计算模块:从数据到模型,再到工程与量化
算法·自动驾驶
Severus_black8 小时前
【C++初阶】list使用及相关实现,思路顺滑流畅!
c语言·数据结构·c++·stl·list
噢,我明白了8 小时前
JAVA中的一些基础应用知识点
java·开发语言