文章转自:http://blog.csdn.net/mymodian9612/article/details/52794980
先直接贴出代码:
#ifndef __WRITE_FIRST_RW_LOCK_H
#define __WRITE_FIRST_RW_LOCK_H
#include <mutex>
#include <condition_variable>
class WfirstRWLock
{
public:
WfirstRWLock() = default;
~WfirstRWLock() = default;
public:
void lock_read()
{
std::unique_lock<std::mutex> ulk(counter_mutex);
cond_r.wait(ulk, [=]()->bool {return write_cnt == 0; });
++read_cnt;
}
void lock_write()
{
std::unique_lock<std::mutex> ulk(counter_mutex);
++write_cnt;
cond_w.wait(ulk, [=]()->bool {return read_cnt == 0 && !inwriteflag; });
inwriteflag = true;
}
void release_read()
{
std::unique_lock<std::mutex> ulk(counter_mutex);
if (--read_cnt == 0 && write_cnt > 0)
{
cond_w.notify_one();
}
}
void release_write()
{
std::unique_lock<std::mutex> ulk(counter_mutex);
if (--write_cnt == 0)
{
cond_r.notify_all();
}
else
{
cond_w.notify_one();
}
inwriteflag = false;
}
private:
volatile size_t read_cnt{ 0 };
volatile size_t write_cnt{ 0 };
volatile bool inwriteflag{ false };
std::mutex counter_mutex;
std::condition_variable cond_w;
std::condition_variable cond_r;
};
template <typename _RWLockable>
class unique_writeguard
{
public:
explicit unique_writeguard(_RWLockable &rw_lockable)
: rw_lockable_(rw_lockable)
{
rw_lockable_.lock_write();
}
~unique_writeguard()
{
rw_lockable_.release_write();
}
private:
unique_writeguard() = delete;
unique_writeguard(const unique_writeguard&) = delete;
unique_writeguard& operator=(const unique_writeguard&) = delete;
private:
_RWLockable &rw_lockable_;
};
template <typename _RWLockable>
class unique_readguard
{
public:
explicit unique_readguard(_RWLockable &rw_lockable)
: rw_lockable_(rw_lockable)
{
rw_lockable_.lock_read();
}
~unique_readguard()
{
rw_lockable_.release_read();
}
private:
unique_readguard() = delete;
unique_readguard(const unique_readguard&) = delete;
unique_readguard& operator=(const unique_readguard&) = delete;
private:
_RWLockable &rw_lockable_;
};
#endif
可以看出用c++11实现读写锁变得非常简洁,在读取量非常大且写入频率很低的时候,通过一个简单的写入线程计数可以避免大量的 cond_w.notify_one();减少读取线程因此发生的切换。
这里需要注意的是对写操作加锁时是先增加写线程计数再判断条件并等待,释放写锁时减少写线程计数并判断是否还有写操作等待,如果有只能唤醒一个写等待。
另外,直接使用lock、unlock在c++中是不推荐的,推荐采用RAII方法,即类unique_writeguard、unique_readguard。