1. 定义数据结构
readers
:当前持有读锁的线程数。waitWriters
:等待写锁的线程数(用于写优先策略)。writing
:标记是否有写锁被持有。- 互斥锁和条件变量:
mutex
和condition_variable
。
2. 读锁逻辑
- 加锁:
- 加锁条件:没有写锁被持有且没有写线程在等待(写优先)。
- 增加
readers
计数。
- 解锁:
- 减少
readers
计数。 - 若所有读锁释放,唤醒一个等待的写线程。
- 减少
3. 写锁逻辑
- 加锁:
- 增加
waitWriters
计数。 - 加锁条件:没有读锁和写锁被持有。
- 减少
waitWriters
计数,标记writing
为 true。
- 增加
- 解锁:
- 标记
writing
为 false。 - 若还有等待的写线程就唤醒一个写线程;否则唤醒所有的读线程
- 标记
```cpp
#include<iostream>
#include<mutex>
#include<thread>
#include<condition_variable>
using namespace std;
class ReadWriteLock
{
public:
ReadWriteLock():readers(0),writing(false), waitWriters(0){}
void readLock()
{
unique_lock<mutex> lock(mtx);
read_cv.wait(lock, [this]() {return !writing && waitWriters == 0; });
readers++;
}
void readUnlock()
{
unique_lock<mutex> lock(mtx);
if(--readers == 0)
write_cv.notify_one();
}
void writeLock()
{
unique_lock<mutex> lock(mtx);
waitWriters++;
write_cv.wait(lock, [this]() {return readers == 0 && writing == false; });
waitWriters--;
writing = true;
}
void writeUnlock()
{
unique_lock<mutex> lock(mtx);
writing = false;
if (waitWriters > 0)
{
write_cv.notify_one();
}
else read_cv.notify_all();
}
private:
int readers;
int waitWriters;
bool writing;
mutex mtx;
condition_variable read_cv;
condition_variable write_cv;
};
// 测试
static int data_ = 0;
ReadWriteLock rw_lock;
// 读取data的值
void reader()
{
rw_lock.readLock();
cout << "读取 data_ = " << data_ << endl;
rw_lock.readUnlock();
}
// 增加data的值
void writer()
{
rw_lock.writeLock();
data_++;
cout << "写入后 data_ = " << data_ << endl;
rw_lock.writeUnlock();
}
int main()
{
thread r1(reader);
thread w1(writer);
thread w2(writer);
thread r2(reader);
r1.join();
w1.join();
w2.join();
r2.join();
}
补充知识点:
1、unique_lock可以换成lock_guard吗?
答:不可以,wait()函数需要一个unique_lock,因为它需要暂时释放锁,等待条件变量通知后再重新获取锁。如果换成lock_guard不能在wait期间释放锁会导致死锁,因为其他线程无法获得锁来通知条件变量。
2、wait()用法
// 版本1:无谓词
void wait(std::unique_lock<std::mutex>& lock);
// 版本2:带谓词(常用)
template <class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
在 wait() 内部,每次线程被唤醒时(无论是通过 notify 还是虚假唤醒),都会调用 pred()。
只有当 pred() 返回 true 时,wait() 才会返回,否则继续等待。