参考:C++中的RAII_一蓑烟雨任平生 也无风雨也无晴-CSDN博客
C++11实现模板化(通用化)RAII机制_10km的专栏-CSDN博客_c++11 raii
无锁编程:c++11基于atomic实现共享读写锁(写优先)_10km的专栏-CSDN博客
raii.h
#include
#include
namespace gyd {
/* 元模板,如果是const类型则去除const修饰符 */
template
struct no_const {
using type = typename std::conditional::value, typename std::remove_const::type, T>::type;
};
/*
* RAII方式管理申请和释放资源的类
* 对象创建时,执行acquire(申请资源)动作(可以为空函数[]{})
* 对象析构时,执行release(释放资源)动作
* 禁止对象拷贝和赋值
*/
class raii {
public:
using fun_type = std::function;
/* release: 析构时执行的函数
* acquire: 构造函数执行的函数
* default_com:_commit,默认值,可以通过commit()函数重新设置
*/
explicit raii(fun_type release, fun_type acquire = [] {}, bool default_com = true) noexcept :
_commit(default_com), _release(release) {
acquire();
}
/* 对象析构时根据_commit标志执行_release函数 */
~raii() noexcept {
if (_commit)
_release();
}
/* 移动构造函数 允许右值赋值 */
raii(raii&& rv)noexcept :_commit(rv._commit), _release(rv._release) {
rv._commit = false;
};
/* 禁用拷贝构造函数 */
raii(const raii&) = delete;
/* 禁用赋值操作符 */
raii& operator=(const raii&) = delete;
/* 设置_commit标志 */
raii& commit(bool c = true)noexcept { _commit = c; return *this; };
private:
/* 为true时析构函数执行_release */
bool _commit;
protected:
/* 析构时执的行函数 */
std::function _release;
}; /* raii */
/* 用于实体资源的raii管理类
* T为资源类型
* acquire为申请资源动作,返回资源T
* release为释放资源动作,释放资源T
*/
template
class raii_var {
public:
using _Self = raii_var;
using acq_type = std::function;
using rel_type = std::function;
explicit raii_var(acq_type acquire, rel_type release) noexcept :
_resource(acquire()), _release(release) {
//构造函数中执行申请资源的动作acquire()并初始化resource;
}
/* 移动构造函数 */
raii_var(raii_var&& rv) :
_resource(std::move(rv._resource)),
_release(std::move(rv._release))
{
rv._commit = false;//控制右值对象析构时不再执行_release
}
/* 对象析构时根据_commit标志执行_release函数 */
~raii_var() noexcept {
if (_commit)
_release(_resource);
}
/* 设置_commit标志 */
_Self& commit(bool c = true)noexcept { _commit = c; return *this; };
/**重点内容*** 获取资源引用 */
T& get() noexcept { return _resource; }
T& operator*() noexcept
{
return get();
}
/* 根据 T类型不同选择不同的->操作符模板 */
template
typename std::enable_if::value, _T>::type operator->() const noexcept
{
return _resource;
}
template
typename std::enable_if::value, _T*>::type operator->() const noexcept
{
return std::addressof(_resource);
}
private:
/* 为true时析构函数执行release */
bool _commit = true;
T _resource;
rel_type _release;
};
/* 创建 raii 对象,
* 用std::bind将M_REL,M_ACQ封装成std::function创建raii对象
* RES 资源类型
* M_REL 释放资源的成员函数地址
* M_ACQ 申请资源的成员函数地址
*/
template
raii make_raii(RES & res, M_REL rel, M_ACQ acq, bool default_com = true)noexcept {
// 编译时检查参数类型
// 静态断言中用到的is_class,is_member_function_pointer等是用于编译期的计算、查询、判断、转换的type_traits类,
// 有点类似于java的反射(reflect)提供的功能,不过只能用于编译期,不能用于运行时。
// 关于type_traits的详细内容参见:http://www.cplusplus.com/reference/type_traits/
static_assert(std::is_class::value, "RES is not a class or struct type.");
static_assert(std::is_member_function_pointer::value, "M_REL is not a member function.");
static_assert(std::is_member_function_pointer::value, "M_ACQ is not a member function.");
assert(nullptr != rel && nullptr != acq);
auto p_res = std::addressof(const_cast::type&>(res));
return raii(std::bind(rel, p_res), std::bind(acq, p_res), default_com);
}
/* 创建 raii 对象 无需M_ACQ的简化版本 */
template
raii make_raii(RES & res, M_REL rel, bool default_com = true)noexcept {
static_assert(std::is_class::value, "RES is not a class or struct type.");
static_assert(std::is_member_function_pointer::value, "M_REL is not a member function.");
assert(nullptr != rel);
auto p_res = std::addressof(const_cast::type&>(res));
return raii(std::bind(rel, p_res), [] {}, default_com);
}
} /* namespace gyd*/
RWLock.h
#include
#include
#include
#include
#include
#include "raii.h"
using namespace gyd;
/*
* atomic实现读写资源锁,独占写,共享读,禁止复制构造函数和'='赋值操作符
* WRITE_FIRST为true时为写优先模式,如果有线程等待读取(m_writeWaitCount>0)则等待,优先让写线程先获取锁
* 允许嵌套加锁
* readLock/Unlock 实现共享的读取加/解锁,线程数不限
* writeLock/Unlock 实现独占的写入加/解锁,同时只允许一个线程写入,
* 当有线程在读取时,写入线程阻塞,当写入线程执行时,所有的读取线程都被阻塞。
*/
class RWLock {
#define WRITE_LOCK_STATUS -1
#define FREE_STATUS 0
private:
/* 初始为0的线程id */
static const std::thread::id NULL_THEAD;
const bool WRITE_FIRST;
/* 用于判断当前是否是写线程 */
std::thread::id m_write_thread_id;
/* 资源锁计数器,类型为int的原子成员变量,-1为写状态,0为自由状态,>0为共享读取状态 */
std::atomic_int m_lockCount;
/* 等待写线程计数器,类型为unsigned int的原子成员变量*/
std::atomic_uint m_writeWaitCount;
public:
// 禁止复制构造函数
RWLock(const RWLock&) = delete;
// 禁止对象赋值操作符
RWLock& operator=(const RWLock&) = delete;
//RWLock& operator=(const RWLock&) volatile = delete;
RWLock(bool writeFirst = false);;//默认为读优先模式
virtual ~RWLock() = default;
int readLock();
int readUnlock();
int writeLock();
int writeUnlock();
//other class defineition code....
static auto make_read_guard(RWLock &lock)->decltype(make_raii(lock, &RWLock::readUnlock, &RWLock::readLock, true)) {
return make_raii(lock, &RWLock::readUnlock, &RWLock::readLock, true);
}
//other class defineition code....
static auto make_write_guard(RWLock &lock)->decltype(make_raii(lock, &RWLock::writeUnlock, &RWLock::writeLock, true)) {
return make_raii(lock, &RWLock::writeUnlock, &RWLock::writeLock, true);
}
// 将读取锁的申请和释放动作封装为raii对象,自动完成加锁和解锁管理
raii read_guard()const noexcept {
return make_raii(*this, &RWLock::readUnlock, &RWLock::readLock);
}
// 将写入锁的申请和释放动作封装为raii对象,自动完成加锁和解锁管理
raii write_guard()noexcept {
return make_raii(*this, &RWLock::writeUnlock, &RWLock::writeLock);
}
};
RWLock.cpp
#include "RWLock.h"
RWLock::RWLock(bool writeFirst) :
WRITE_FIRST(writeFirst),
m_write_thread_id(),
m_lockCount(0),
m_writeWaitCount(0) {
}
int RWLock::readLock() {
// ==时为独占写状态,不需要加锁
if (std::this_thread::get_id() != this->m_write_thread_id) {
int count;
if (WRITE_FIRST)//写优先模式下,要检测等待写的线程数为0(m_writeWaitCount==0)
do {
while ((count = m_lockCount) == WRITE_LOCK_STATUS || m_writeWaitCount > 0);//写锁定时等待
} while (!m_lockCount.compare_exchange_weak(count, count + 1));
else
do {
while ((count = m_lockCount) == WRITE_LOCK_STATUS); //写锁定时等待
} while (!m_lockCount.compare_exchange_weak(count, count + 1));
}
return m_lockCount;
}
int RWLock::readUnlock() {
// ==时为独占写状态,不需要加锁
if (std::this_thread::get_id() != this->m_write_thread_id)
--m_lockCount;
return m_lockCount;
}
int RWLock::writeLock() {
// ==时为独占写状态,避免重复加锁
if (std::this_thread::get_id() != this->m_write_thread_id) {
++m_writeWaitCount;//写等待计数器加1
// 没有线程读取时(加锁计数器为0),置为-1加写入锁,否则等待
for (int zero = FREE_STATUS; !this->m_lockCount.compare_exchange_weak(zero, WRITE_LOCK_STATUS); zero = FREE_STATUS);
--m_writeWaitCount;//获取锁后,计数器减1
m_write_thread_id = std::this_thread::get_id();
}
return m_lockCount;
}
int RWLock::writeUnlock() {
if (std::this_thread::get_id() != this->m_write_thread_id) {
throw std::runtime_error("writeLock/Unlock mismatch");
}
assert(WRITE_LOCK_STATUS == m_lockCount);
m_write_thread_id = NULL_THEAD;
m_lockCount.store(FREE_STATUS);
return m_lockCount;
}
const std::thread::id RWLock::NULL_THEAD;
调用方式
RWLock lock;
void make_raii_test(){
auto guard=RWLock::make_read_guard(lock);
//do something...
}
int main(){
make_raii_test();
}
RWLock lock;
void make_raii_test(){
auto guard=RWLock::make_write_guard(lock);
//do something...
}
int main(){
make_raii_test();
}