c++ 11读写锁

参考: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();
}

你可能感兴趣的:(c++,c++,git,html5)