绞尽脑汁写的一个自认为非常简洁高效的读写锁
2009-03-20 03:31
381 查看
以前的工作中用到过几次读写锁,自己还曾实现过一两个版本(现在回头看看都很垃圾),剩下大部分用别人库里的。
两个月前一个小项目里需要一个读写锁,对效率要求很高。某天下午终于花了几个小时的时间设计出这么一个东东,理论上看,非常简洁高效,但逻辑较混乱……没办法为了高效嘛,只好牺牲点了。
其后的几天,通过写程序来完全模拟读写锁行为,发现了多个逻辑错误导致死锁或未锁的情况, 好在最后牺牲了更多的脑细胞后,终于完成了一个严格通过模拟逻辑测试的版本。
简单介绍下,能想到的,这个读写锁的特点:
一、数据结构简单,仅使用两个event对象和两个计数变量,整个读写锁共16字节大小。实现部分只有50多行代码。
二、作为写优先的读写锁,支持多个写线程。
三、其工作方式非常高效。在没有线程执行写操作时,其读锁的获取和释放过程不产生任何系统调用。
四、整个工作过程不存在轮询等待——正常地写都如此吧,无奈翻翻我以前写过的第一个读写锁程序……汗。
五、可以通过简单的修改,将两个event对象命名,且移动两个计数变量到共享内存中,即可在多个进程间使用。
以下是源码:
两个月前一个小项目里需要一个读写锁,对效率要求很高。某天下午终于花了几个小时的时间设计出这么一个东东,理论上看,非常简洁高效,但逻辑较混乱……没办法为了高效嘛,只好牺牲点了。
其后的几天,通过写程序来完全模拟读写锁行为,发现了多个逻辑错误导致死锁或未锁的情况, 好在最后牺牲了更多的脑细胞后,终于完成了一个严格通过模拟逻辑测试的版本。
简单介绍下,能想到的,这个读写锁的特点:
一、数据结构简单,仅使用两个event对象和两个计数变量,整个读写锁共16字节大小。实现部分只有50多行代码。
二、作为写优先的读写锁,支持多个写线程。
三、其工作方式非常高效。在没有线程执行写操作时,其读锁的获取和释放过程不产生任何系统调用。
四、整个工作过程不存在轮询等待——正常地写都如此吧,无奈翻翻我以前写过的第一个读写锁程序……汗。
五、可以通过简单的修改,将两个event对象命名,且移动两个计数变量到共享内存中,即可在多个进程间使用。
以下是源码:
/******************************************************************** created: 2009/01/16 created: 16:1:2009 3:35 name: ReadWriteLock 1.0 filename: ReadWriteLock.h author: Foreverflying *********************************************************************/ #pragma once #include <intrin.h> class ReadWriteLock { public: ReadWriteLock(void); ~ReadWriteLock(void); void GetReadLock(); void ReleaseReadLock(); void GetWriteLock(); void ReleaseWriteLock(); private: BOOL StopRead_WaitSetWrite(); HANDLE _canReadEvent; HANDLE _canWriteEvent; volatile LONG _readCount; volatile LONG _writeCount; }; #define CAN_NOT_READ_SIGN 0x80000000 #define CAN_NOT_WRITE_SIGN 0x40000000 #define READ_COUNT_MASK 0x3fffffff ReadWriteLock::ReadWriteLock(void) : _readCount(0) , _writeCount(0) { _canReadEvent = CreateEvent( NULL, TRUE, TRUE, NULL ); _canWriteEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); } ReadWriteLock::~ReadWriteLock( void ) { CloseHandle( _canReadEvent ); CloseHandle( _canWriteEvent ); } void ReadWriteLock::GetReadLock() { while(1){ LONG count = InterlockedIncrement( &_readCount ); if( count < 0 ){ InterlockedDecrement( &_readCount ); count = InterlockedCompareExchange( &_readCount, CAN_NOT_READ_SIGN, CAN_NOT_READ_SIGN | CAN_NOT_WRITE_SIGN ); if( count == (CAN_NOT_READ_SIGN | CAN_NOT_WRITE_SIGN) ){ SetEvent( _canWriteEvent ); } WaitForSingleObject( _canReadEvent, INFINITE ); }else{ return; } } } void ReadWriteLock::ReleaseReadLock() { InterlockedDecrement( &_readCount ); LONG count = InterlockedCompareExchange( &_readCount, CAN_NOT_READ_SIGN, CAN_NOT_READ_SIGN | CAN_NOT_WRITE_SIGN ); if( count == (CAN_NOT_READ_SIGN | CAN_NOT_WRITE_SIGN) ){ SetEvent( _canWriteEvent ); } } void ReadWriteLock::GetWriteLock() { LONG count = InterlockedIncrement( &_writeCount ); if( count == 1 ){ if( !StopRead_WaitSetWrite() ){ return; } } WaitForSingleObject( _canWriteEvent, INFINITE ); } void ReadWriteLock::ReleaseWriteLock() { LONG count = _writeCount; if( count == 1 ){ _InterlockedAnd( &_readCount, ~CAN_NOT_READ_SIGN ); SetEvent( _canReadEvent ); count = InterlockedDecrement( &_writeCount ); if( !count ){ return; } if( StopRead_WaitSetWrite() ){ return; } }else{ InterlockedDecrement( &_writeCount ); } SetEvent( _canWriteEvent ); } BOOL ReadWriteLock::StopRead_WaitSetWrite() { ResetEvent( _canReadEvent ); LONG count = _InterlockedOr( &_readCount, CAN_NOT_READ_SIGN ); if( count ){ _InterlockedOr( &_readCount, CAN_NOT_WRITE_SIGN ); count = InterlockedCompareExchange( &_readCount, CAN_NOT_READ_SIGN, CAN_NOT_READ_SIGN | CAN_NOT_WRITE_SIGN ); if( count != (CAN_NOT_READ_SIGN | CAN_NOT_WRITE_SIGN) ){ return TRUE; } } return FALSE; }
相关文章推荐
- 一个非常简洁高效的JS右键菜单!
- 非常简洁高效的JS右键菜单
- 推荐一个轻量、简洁、高效、跨平台的代码编辑器
- 自定义View_一个非常简洁的柱状图
- 开源造轮子:一个简洁,高效,轻量级,酷炫的不要不要的canvas粒子运动插件库
- [ASP]一个非常简洁的验证码程序
- 一个非常简洁的验证码程序
- 分享一个自己写的table表格排序js插件(高效简洁)
- 一个非常高效的去重且保持原顺序算法
- 一个高效简洁的Struts分页方法(转)
- 分页---一个高效简洁的Struts分页方法
- 给定一个非常长的字节序列(假设有十亿或万亿),如何高效的统计1的个数
- 分享一个自己写的table表格排序js插件(高效简洁)
- Hexo 是一个快速、简洁且高效的博客框架
- 一个非常简洁的 jQuery 图片轮播插件
- 删除有序数组中重复元素的一个非常简洁的算法
- 通过Vim+少量插件配置一个高效简洁的IDE
- 一个高效简洁的Struts分页方法
- 一步一步封装一个简洁高效可拓展的Adapter
- 一个高效简洁的Struts分页方法(原创)