一. 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);
