锁
锁
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_;
};
浙公网安备 33010602011771号