目录
- 锁
- 1. 锁的分类
- 1.1 自旋锁
- 1.2 互斥锁
- 手撕读写锁
- 1. 读写锁的原理
- 2. 读写锁的实现
- 2.1 读写锁的接口设计
- 2.2 读写锁的实现
- 1. 锁的分类
锁
1. 锁的分类
1.1 自旋锁
自旋锁是一种忙等待锁,当线程获取锁失败时,会一直循环等待,直到获取到锁为止。
自旋锁的优点是避免了线程切换的开销,缺点是如果锁竞争激烈,会导致CPU资源浪费。
1.2 互斥锁
互斥锁是一种阻塞锁,当线程获取锁失败时,会阻塞当前线程,直到获取到锁为止。
互斥锁的优点是可以保证线程安全,缺点是可能会导致线程阻塞,影响程序性能。
手撕读写锁
1. 读写锁的原理
读写锁,又称为共享-独占锁,是计算机程序的并发控制的一种同步机制,它允许多个线程同时读取共享数据,但是只允许一个线程写入共享数据,在写入共享数据时,会独占锁,其他线程不能读取也不能写入。
读写锁主要包含以下几个要点:
- 读锁:允许多个线程同时获取读锁,但是不能获取写锁。
- 写锁:只能有一个线程获取写锁,其他线程不能获取读锁和写锁。
- 写锁优先级:当一个线程获取了写锁,其他线程不能获取读锁和写锁,直到写锁被释放。(推荐)
- 读锁优先级:当一个线程获取了读锁,其他线程可以继续获取读锁,但是不能获取写锁,直到所有读锁被释放,需注意写饥饿问题。
- 公平优先:读写锁是否公平,即获取锁的顺序是否按照请求的顺序。
读写锁的实现需要考虑以下几个问题:
- 如何实现读锁和写锁的互斥?
两个条件变量,一个用于读锁,一个用于写锁。 - 如何实现读锁和写锁的优先级?
- 如何实现读锁和写锁的同步?
使用三个变量,一个记录活跃读者的数量,一个记录等待写者的数量,一个标记是否有活跃写者,只用等待写者数量无法准确判断是否有读者在写入。
2. 读写锁的实现
2.1 读写锁的接口设计
class Lock{
private:std::mutex mtx_;public:Lock(){};~Lock(){};void lock(){ mtx_.lock(); }void unlock(){ mtx_.unlock(); }std::mutex& getMutex(){ return &mtx_; }
};class RWLock {
public:RWLock();~RWLock();void readLock();void readUnlock();void writeLock();void writeUnlock();private:// 读写锁的成员变量Lock base_lock_;std::condition_variable read_cv_;std::condition_variable write_cv_;int active_readers_ = 0; // 活跃读者数量int waiting_writers_ = 0; // 等待写者数量bool active_writer_ = false; // 是否有活跃写者
};
2.2 读写锁的实现
RWLock::RWLock() {active_readers_ = 0;waiting_writers_ = 0;active_writer_ = false;
}RWLock::~RWLock() {active_readers_ = 0;waiting_writers_ = 0;active_writer_ = false;
}void RWLock::readLock() {std::unique_lock<std::mutex> lock(base_lock_.getMutex());// 如果没有活跃写者,并且没有等待的写者,则获取读锁read_cv_.wait(lock, [this]() {return !active_writer_ && waiting_writers_ == 0;});active_readers_++;
}
void RWLock::readUnlock() {std::unique_lock<std::mutex> lock(base_lock_.getMutex());active_readers_--;// 如果没有活跃读者,并且有等待的写者,则通知写者if (active_readers_ == 0 && waiting_writers_ > 0) {write_cv_.notify_one();}
}void RWLock::writeLock() {std::unique_lock<std::mutex> lock(base_lock_.getMutex());// 如果没有活跃读者,并且没有活跃写者,则获取写锁waiting_writers_++;write_cv_.wait(lock, [this]() {return !active_writer_ && active_readers_ == 0;});waiting_writers_--;active_writer_ = true;
}void RWLock::writeUnlock() {std::unique_lock<std::mutex> lock(base_lock_.getMutex());active_writer_ = false;// 如果有等待的写者,则通知写者if (waiting_writers_ > 0) {write_cv_.notify_one();}// 如果有等待的读者,则通知读者else if (active_readers_ > 0) {read_cv_.notify_all();}
}//RAII 写法
class ReadLock {
public:ReadLock(RWLock& rwlock) : rwlock_(rwlock) {rwlock_.readLock();}~ReadLock() {rwlock_.readUnlock();}// 禁用拷贝构造函数和赋值运算符ReadLock(const ReadLock&) = delete;ReadLock& operator=(const ReadLock&) = delete;private:RWLock& rwlock_;
};class WriteLock {
public:WriteLock(RWLock& rwlock) : rwlock_(rwlock) {rwlock_.writeLock();}~WriteLock() {rwlock_.writeUnlock();}// 禁用拷贝构造函数和赋值运算符WriteLock(const WriteLock&) = delete;WriteLock& operator=(const WriteLock&) = delete;private:RWLock& rwlock_;
};