无锁编程:c++11基于atomic实现共享读写锁(写优先)
来源:互联网 发布:java调用soap接口实例 编辑:程序博客网 时间:2024/05/17 07:36
在多线程状态下,对一个对象的读写需要加锁,基于CAS指令的原子语句可以实现高效的线程间协调。关于CAS的概念参见下面的文章:
无锁编程以及CAS
在c++11中CAS指令已经被封装成了 非常方便使用的atomic模板类, 详情参见:
atomic参考
以下代码利用atomic
实现了一个读写资源锁,并且可以根据需要通过构造函数参数设置成写优先(write_first)(代码在gcc5和vs2015下编译通过):
readLock/Unlock 实现共享的读取加/解锁,线程数不限,有读取线程工作时,所有的申请写入线程都会等待
writeLock/Unlock 实现独占的写入加/解锁,同时只允许一个线程写入,当有线程在读取时,写入线程等待,当写入线程执行时,所有的读取线程都被等待。
locck/unlock语句允许嵌套
比如
lock.readLock();lock.readLock();...lock.readUnlock();lock.readUnlock();
也允许在写入状态下嵌套读取,比如
lock.writeLock();lock.writeLock();lock.readLock();...lock.readUnlock();lock.writeUnlock();lock.writeUnlock();
RWLock.h
#include <cstdlib>#include <cassert>#include <atomic>#include <thread>#include "raii.h"/* * atomic实现读写资源锁,独占写,共享读,禁止复制构造函数和'='赋值操作符 * WRITE_FIRST为true时为写优先模式,如果有线程等待读取(m_writeWaitCount>0)则等待,优先让写线程先获取锁 * 允许嵌套加锁 * readLock/Unlock 实现共享的读取加/解锁,线程数不限 * writeLock/Unlock 实现独占的写入加/解锁,同时只允许一个线程写入, * 当有线程在读取时,写入线程阻塞,当写入线程执行时,所有的读取线程都被阻塞。 */class RWLock {#define WRITE_LOCK_STATUS -1#define FREE_STATUS 0private: /* 初始为0的线程id */ static const std::thread::id NULL_THEAD; const bool WRITE_FIRST; /* 用于判断当前是否是写线程 */ thread::id m_write_thread_id; /* 资源锁计数器,类型为int的原子成员变量,-1为写状态,0为自由状态,>0为共享读取状态 */ atomic_int m_lockCount; /* 等待写线程计数器,类型为unsigned int的原子成员变量*/ 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(); // 将读取锁的申请和释放动作封装为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
RWLock::RWLock(bool writeFirst): WRITE_FIRST(writeFirst), m_write_thread_id(), m_lockCount(0), m_writeWaitCount(0){}int RWLock::readLock() { // ==时为独占写状态,不需要加锁 if (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 (this_thread::get_id() != this->m_write_thread_id) --m_lockCount; return m_lockCount;}int RWLock::writeLock(){ // ==时为独占写状态,避免重复加锁 if (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=this_thread::get_id(); } return m_lockCount;}int RWLock::writeUnlock(){ if(this_thread::get_id() != this->m_write_thread_id){ throw 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;
说明1
atomic_int,atomic_uint
都是从atomic
类模板中派生出来的类,对应不同的数据类型
atomic是c++11标准,在gcc编译的时候必须加入std=c++11选项才能正确编译,,vs编译至少要用vs2012,因为visual studio 2012以上才支持atomic模板
说明2
如果按照默认的类定义方法,提供复制构造函数和赋值操作符=
,那么可以想见,在应用中可能会产生不可预知的问题,所以参照atomic
模板的写法,加入了禁止复制构造函数和对象复制操作符=
的代码,
//禁止复制构造函数 RWLock(const RWLock&) = delete; //禁止对象赋值操作符 RWLock& operator=(const RWLock&) = delete; RWLock& operator=(const RWLock&) volatile = delete;
说明3
这个代码还有欠缺的地方就是没有实现超时异常中止。
说明4
read_guard,write_guard
函数返回的raii
类参见我的另一篇博客《C++11实现模板化(通用化)RAII机制》
- 无锁编程:c++11基于atomic实现共享读写锁(写优先)
- 基于互斥锁和条件变量实现读写锁,写优先
- 使用Boost的共享锁、条件变量、原子操作实现写优先的读写锁
- 一个写优先的读写锁实现
- c++11实现写优先的读写锁
- c++11实现写优先的读写锁
- 利用信号实现写优先的读写锁
- 使用sdl接口实现的读写锁,非写优先
- JAVA无锁编程--Atomic包的使用
- linux 读写锁(写优先)使用方法
- pthread读写锁,写优先设置
- 无锁之Atomic大杂烩
- 读写锁 共享读 独占写
- c++实现读写共享锁
- c++实现读写共享锁
- c++实现读写共享锁
- c++实现读写共享锁
- 一个Windows下C++读写锁的代码,实现共享读,独占写
- MySQL索引背后的数据结构及算法原理--转
- iOS9 UIPopoverViewController
- Tomcat和eclipse连接
- 推排序算法C/C++
- linux下的多进程编程
- 无锁编程:c++11基于atomic实现共享读写锁(写优先)
- 深入分析 Linux 内核链表--转
- iOS开发--多线程(NSThread,NSOperation,GCD)
- bits/stdc++.h
- hdu 3113 Sum of Cubes 数学 枚举 剪枝
- 地图和定位
- iOS开发日常安全防护(一)
- js的with语句
- java---表、栈和队列