读写锁,一直都有听,也大概知道点原理,一直没有探究内部是如何实现的,正好今天完成了几项大作业,研究一下读写锁实现的原理。
读写锁的原理就是,可以多次读,但是写只能一次一次的写入,我参考的源码博主控制了写优先,并且读的优先级没我写的这么高。我自己在修改了他的源码,实现的是读优先,并且优先级很高,如果存在大量的读操作,可能会出现写操作线程饥饿的现象。如果在具体的场景中写操作也多,可以修改wait条件来判断优先级。我最近的感悟,如果非必要,一个类的对象不必非要跨线程操作。对象不跨线程操作,也就不涉及这种饥饿问题了
#include<mutex>
#include<condition_variable>
#include<iostream>
#include<vector>
#include<thread>
using namespace std;
class ReadWriteLock {
private:
int readWaiting = 0; //等待读
int writeWaiting = 0; //等待写
int reading = 0; //正在读
int writing = 0; //正在写
std::mutex mx;
std::condition_variable cond;
bool preferWriter; //偏向读
public:
ReadWriteLock(bool isPreferWriter = false) :preferWriter(isPreferWriter) {}
void readLock() {
std::unique_lock<std::mutex>lock(mx);
++readWaiting;
// preferWriter靠这个来让写锁优先了
//cond.wait(lock, [&]() {return writing <= 0 && (!preferWriter || writeWaiting <= 0); });
// 读锁优先
cond.wait(lock,[&](){return writing <= 0;});
++reading;
--readWaiting;
}
void writeLock() {
std::unique_lock<std::mutex>lock(mx);
++writeWaiting;
// 这里规定writing<=0才能继续执行,保证了写的时候进入一次,reading <= 0 保证了读的优先
cond.wait(lock, [&]() {return readWaiting <=0 && reading <= 0 && writing <= 0; });
++writing;
--writeWaiting;
}
void readUnLock() {
std::unique_lock<std::mutex>lock(mx);
--reading;
//当前没有读者时,唤醒一个写者
if(reading<=0)
cond.notify_one();
}
void writeUnLock() {
std::unique_lock<std::mutex>lock(mx);
--writing;
//唤醒所有读者、写者
cond.notify_all();
}
};
//true 为写者优先,不过我修改了源码,true或者false都没有意义了
ReadWriteLock readWriteLock(false);
// 锁都是要等三秒钟才释放锁
void reader() {
readWriteLock.readLock();
cout << "reader" << endl;
this_thread::sleep_for(std::chrono::seconds(3));
readWriteLock.readUnLock();
}
void writer() {
readWriteLock.writeLock();
cout << "writer" << endl;
this_thread::sleep_for(std::chrono::seconds(3));
readWriteLock.writeUnLock();
}
int main() {
vector<thread>vec;
for (int i = 0; i < 5; ++i) {
vec.push_back(thread(reader));
vec.push_back(thread(writer));
}
for (int i = 0; i < vec.size(); ++i) {
if(vec[i].joinable())
vec[i].join();
}
}