读写锁 share_mutex
来源:互联网 发布:.com域名怎么续费 编辑:程序博客网 时间:2024/05/16 09:58
作者:tyc611.cublog.cn,2008-11-18
在Windows Vista/Server 2008之前,Windows没有提供共享锁(通俗称为读写锁),只能靠自己实现。但从Windows Vista/Server 2008开始,Windows提供了用户态下的读写锁SRWLock,效率非常高。本文实现了一个简单的共享锁,可用于之前的Windows系统。
实现原理:
锁内部会记录当前锁类型、共享访问线程数和互斥访问线程数,并利用互斥量来保护这些内部数据,使用事件来实现共享访问线程和互斥访问线程的同步。
这里,使用了互斥量来保护数据,效率较低(因为必须进入内核态)。但如果使用临界区来进行保护,则无法保证离开临界区同时等待事件触发的原子性。有时间进一步研究是否可以使用临界区来代替这里的互斥量。
下面的类被命名为SharedMutex(可共享的互斥量),而不是SharedLock,原因是SharedMutex提供了共享锁的基本功能,可以直接使用。但为了使用方便,可以在此基础上包装出另一个更方便的共享锁SharedLock,这个在后续文章中给出实现。
类SharedMutex的源代码(文章后面附有打包下载):
/**
* SharedMutex.h
* @Author Tu Yongce
* @Created 2008-11-17
* @Modified 2008-11-17
* @Version 0.1
*/
#ifndef SHARED_MUTEX_H_INCLUDED
#define SHARED_MUTEX_H_INCLUDED
#ifndef _WIN32
#error "works only on Windows"
#endif
#include <windows.h>
#include "Noncopyable.h"
// 可共享的互斥量
class SharedMutex
: private Noncopyable
{
private:
HANDLE m_mutex;
HANDLE m_sharedEvent;
HANDLE m_exclusiveEvent;
volatile int m_sharedNum;
volatile int m_exclusiveNum;
volatile int m_lockType;
static constint LOCK_NONE = 0;
static constint LOCK_SHARED = 1;
static constint LOCK_EXCLUSIVE = 2;
public:
SharedMutex();
~SharedMutex();
// 获取共享访问权
bool AcquireShared(DWORD waitTime= INFINITE);
// 释放共享访问权
void ReleaseShared();
// 获取独占访问权
bool AcquireExclusive(DWORD waitTime= INFINITE);
// 释放独占访问权
void ReleaseExclusive();
};
#endif // SHARED_MUTEX_H_INCLUDED
/**
* SharedMutex.cpp
* @Author Tu Yongce
* @Created 2008-11-17
* @Modified 2008-11-17
* @Version 0.1
*/
#include "SharedMutex.h"
#include <cassert>
SharedMutex::SharedMutex(): m_sharedNum(0), m_exclusiveNum(0), m_lockType(LOCK_NONE)
{
// 创建用于保护内部数据的互斥量
m_mutex = ::CreateMutex(NULL,FALSE, NULL);
// 创建用于同步共享访问线程的事件(手动事件)
m_sharedEvent = ::CreateEvent(NULL,TRUE, FALSE, NULL);
// 创建用于同步独占访问线程的事件(自动事件)
m_exclusiveEvent = ::CreateEvent(NULL,FALSE, FALSE, NULL);
}
SharedMutex::~SharedMutex()
{
::CloseHandle(m_mutex);
::CloseHandle(m_sharedEvent);
::CloseHandle(m_exclusiveEvent);
}
// 获取共享访问权
bool SharedMutex::AcquireShared(DWORD waitTime)
{
::WaitForSingleObject(m_mutex, INFINITE);
++m_sharedNum;
if (m_lockType== LOCK_EXCLUSIVE){
DWORD retCode = ::SignalObjectAndWait(m_mutex, m_sharedEvent, waitTime,FALSE);
if (retCode== WAIT_OBJECT_0){
return true;
} else {
if (retCode== WAIT_TIMEOUT)
::SetLastError(WAIT_TIMEOUT);
return false;
}
}
m_lockType = LOCK_SHARED;
::ReleaseMutex(m_mutex);
return true;
}
// 释放共享访问权
void SharedMutex::ReleaseShared()
{
assert(m_lockType== LOCK_SHARED);
::WaitForSingleObject(m_mutex, INFINITE);
--m_sharedNum;
if (m_sharedNum== 0){
if (m_exclusiveNum> 0) {
// 唤醒一个独占访问线程
m_lockType = LOCK_EXCLUSIVE;
::SetEvent(m_exclusiveEvent);
} else {
// 没有等待线程
m_lockType = LOCK_NONE;
}
}
::ReleaseMutex(m_mutex);
}
// 获取独占访问权
bool SharedMutex::AcquireExclusive(DWORD waitTime)
{
::WaitForSingleObject(m_mutex, INFINITE);
++m_exclusiveNum;
if (m_lockType!= LOCK_NONE){
DWORD retCode = ::SignalObjectAndWait(m_mutex, m_exclusiveEvent, waitTime,FALSE);
if (retCode== WAIT_OBJECT_0){
return true;
} else {
if (retCode== WAIT_TIMEOUT)
::SetLastError(WAIT_TIMEOUT);
return false;
}
}
m_lockType = LOCK_EXCLUSIVE;
::ReleaseMutex(m_mutex);
return true;
}
// 释放独占访问权
void SharedMutex::ReleaseExclusive()
{
assert(m_lockType== LOCK_EXCLUSIVE);
::WaitForSingleObject(m_mutex, INFINITE);
--m_exclusiveNum;
// 独占访问线程优先
if (m_exclusiveNum> 0) {
// 唤醒一个独占访问线程
::SetEvent(m_exclusiveEvent);
} else if (m_sharedNum > 0) {
// 唤醒当前所有共享访问线程
m_lockType = LOCK_SHARED;
::PulseEvent(m_sharedEvent);
} else {
// 没有等待线程
m_lockType = LOCK_NONE;
}
::ReleaseMutex(m_mutex);
}
SharedMutex的测试代码:
/**
* SharedMutex_example.cpp
* @Author Tu Yongce
* @Created 2008-11-17
* @Modified 2008-11-17
* @Version 0.1
*/
#include <process.h>
#include <iostream>
#include "SharedMutex.h"
using namespacestd;
SharedMutex g_mutex;
const int LOOP_NUM= 2000;
volatile __int64 g_data = 0;
CRITICAL_SECTION g_cs;
unsigned WINAPI ReaderThread(void*pParam)
{
int id = (int)pParam;
::EnterCriticalSection(&g_cs);
cout <<"Reader [" << id<< "] start" <<endl;
::LeaveCriticalSection(&g_cs);
__int64 max = 0;
__int64 min = 0;
for (int i= 0; i < LOOP_NUM; ++i){
g_mutex.AcquireShared();
__int64 data = g_data;
if (data> max)
max = data;
if (data< min)
min = data;
g_mutex.ReleaseShared();
Sleep(1);
}
::EnterCriticalSection(&g_cs);
cout <<"Reader [" << id<< "] quit, max = " <<max <<", min = " <<min <<endl;
::LeaveCriticalSection(&g_cs);
return 0;
}
unsigned WINAPI WriterThread1(void*pParam)
{
int id = (int)pParam;
::EnterCriticalSection(&g_cs);
cout <<"Writer1 [" << id<< "] start" <<endl;
::LeaveCriticalSection(&g_cs);
for (int i= 0; i < LOOP_NUM; ++i){
g_mutex.AcquireExclusive();
g_data = g_data + i;
g_mutex.ReleaseExclusive();
Sleep(1);
}
::EnterCriticalSection(&g_cs);
cout <<"Writer1 [" << id<< "] quit" <<endl;
::LeaveCriticalSection(&g_cs);
return 0;
}
unsigned WINAPI WriterThread2(void*pParam)
{
int id = (int)pParam;
::EnterCriticalSection(&g_cs);
cout <<"Writer2 [" << id<< "] start" <<endl;
::LeaveCriticalSection(&g_cs);
for (int i= 0; i < LOOP_NUM; ++i){
g_mutex.AcquireExclusive();
g_data = g_data - i;
g_mutex.ReleaseExclusive();
Sleep(1);
}
::EnterCriticalSection(&g_cs);
cout <<"Writer2 [" << id<< "] quit" <<endl;
::LeaveCriticalSection(&g_cs);
return 0;
}
int main()
{
::InitializeCriticalSection(&g_cs);
// 创建读写工作线程(创建时挂起工作线程)
HANDLE readers[20];
for (int i= 0; i < _countof(readers);++i){
readers[i]= (HANDLE)_beginthreadex(NULL, 0, ReaderThread, (void*)i,
CREATE_SUSPENDED, NULL);
}
HANDLE writers1[5];
for (int i= 0; i < _countof(writers1);++i){
writers1[i]= (HANDLE)_beginthreadex(NULL, 0, WriterThread1, (void*)i,
CREATE_SUSPENDED, NULL);
}
HANDLE writers2[5];
for (int i= 0; i < _countof(writers2);++i){
writers2[i]= (HANDLE)_beginthreadex(NULL, 0, WriterThread2, (void*)i,
CREATE_SUSPENDED, NULL);
}
// 恢复工作线程
for (int i= 0; i < _countof(readers);++i){
ResumeThread(readers[i]);
}
for (int i= 0; i < _countof(writers1);++i){
ResumeThread(writers1[i]);
}
for (int i= 0; i < _countof(writers2);++i){
ResumeThread(writers2[i]);
}
// 等待工作线程结束
WaitForMultipleObjects(_countof(readers), readers,TRUE, INFINITE);
WaitForMultipleObjects(_countof(writers1), writers1,TRUE, INFINITE);
WaitForMultipleObjects(_countof(writers2), writers2,TRUE, INFINITE);
// 释放内核对象句柄
for (int i= 0; i < _countof(readers);++i){
CloseHandle(readers[i]);
}
for (int i= 0; i < _countof(writers1);++i){
CloseHandle(writers1[i]);
}
for (int i= 0; i < _countof(writers2);++i){
CloseHandle(writers2[i]);
}
::DeleteCriticalSection(&g_cs);
cout <<">> Expected data value is " << 0 <<", and the real value is " << g_data <<endl;
return 0;
}
编译运行测试:
F:\tmp\SharedLock>cl SharedMutex.cpp SharedMutex_example.cpp /EHsc /Fettt.exe /n
ologo
SharedMutex.cpp
SharedMutex_example.cpp
正在生成代码...
F:\tmp\SharedLock>ttt.exe
Reader [0] start
Reader [1] start
Reader [2] start
Reader [3] start
Reader [4] start
Reader [5] start
Reader [6] start
Reader [7] start
Reader [8] start
Reader [9] start
Reader [10] start
Reader [11] start
Reader [12] start
Reader [13] start
Reader [14] start
Reader [15] start
Reader [16] start
Reader [17] start
Reader [18] start
Reader [19] start
Writer1 [0] start
Writer1 [1] start
Writer1 [2] start
Writer1 [3] start
Writer1 [4] start
Writer2 [0] start
Writer2 [1] start
Writer2 [2] start
Writer2 [3] start
Writer2 [4] start
Reader [3] quit, max = 8352, min = 0
Reader [2] quit, max = 8352, min = -1
Reader [1] quit, max = 9039, min = -3761
Reader [4] quit, max = 8352, min = 0
Reader [6] quit, max = 8352, min = -3453
Reader [8] quit, max = 9039, min = -1758
Reader [5] quit, max = 8352, min = -3453
Reader [0] quit, max = 8352, min = -1758
Reader [10] quit, max = 9460, min = -120
Reader [14] quit, max = 8352, min = 0
Reader [9] quit, max = 8352, min = -120
Reader [11] quit, max = 8352, min = -1758
Reader [12] quit, max = 8352, min = -1721
Reader [15] quit, max = 9460, min = 0
Reader [7] quit, max = 8352, min = -3453
Writer1 [4] quit
Reader [17] quit, max = 9460, min = -3453
Reader [13] quit, max = 8352, min = -3453
Reader [16] quit, max = 8352, min = -3453
Reader [19] quit, max = 8352, min = -120
Writer2 [4] quit
Reader [18] quit, max = 8352, min = -3453
Writer1 [1] quit
Writer2 [1] quit
Writer1 [3] quit
Writer2 [3] quit
Writer2 [0] quit
Writer1 [2] quit
Writer1 [0] quit
Writer2 [2] quit
>> Expected data value is 0, and the real value is 0
- 读写锁 share_mutex
- boost库 学习笔记一 boost::share_mutex 互斥锁 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 读写锁
- 2017.5.21测试 题四 遭遇战
- input文本框绑定回车键事件及火狐浏览器不支持event
- mongodb的安装与使用
- Call分析(二)之ProcessThread和Module
- mac版本webstorm设置编译后的scss文件输出路径
- 读写锁 share_mutex
- OracleLinux的MTU问题
- 基本含概PHP+mysql所有方方面面的面试题,针对性模块性复习,高薪面试必过
- js中forEach、map
- MySQL的安装(详细图解)
- 利用Console来调试JS程序、Console用法总结
- redis之 centos 6.7 下安装 redis-3.2.5
- JS秘技--焦点轮播图
- yii1.1 数据save后得到插入id