Skip to content

Instantly share code, notes, and snippets.

@ccnyou
Last active October 28, 2020 07:05
Show Gist options
  • Save ccnyou/d2ce9c08c19ae3da2a3cd700dd293e2e to your computer and use it in GitHub Desktop.
Save ccnyou/d2ce9c08c19ae3da2a3cd700dd293e2e to your computer and use it in GitHub Desktop.
大学时候使用C++在Windows环境下实现的读写锁
class CXxx
{
//other code...
cc::CSharedMutex m_xxxMutex; // 声明要互斥变量
}
CXxx::SomeMethod()
{
{ //限定锁的作用域
//readLock 是变量名,可以随意指定
//READ_LOCK(readLock, &m_xxxMutex);
WRITE_LOCK(writeLock, &m_xxxMutex);
//使用互斥资源
//...
}
}
#include "StdAfx.h"
#include "ReadWriteLock.h"
#include <assert.h>
namespace cc
{
CSharedMutex::CSharedMutex( void )
{
m_hWriteEvent = NULL;
m_hReadEvent = NULL;
m_currentLevel = LockLevelNone;
m_nReadingCount = 0;
}
CSharedMutex::~CSharedMutex(void)
{
Uninit();
}
BOOL CSharedMutex::Init()
{
//在写数据和读数据的时候,m_hWriteEvent无信号
m_hWriteEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
//在读数据的时候, m_hReadEvent和m_hWriteEvent都无信号
m_hReadEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
m_currentLevel = LockLevelNone;
m_nReadingCount = 0;
InitializeCriticalSection(&m_csStateChange);
return TRUE;
}
BOOL CSharedMutex::Uninit()
{
if (m_currentLevel != LockLevelNone)
{
Unlock();
}
DeleteCriticalSection(&m_csStateChange);
if (m_hWriteEvent)
{
CloseHandle(m_hWriteEvent);
m_hWriteEvent = NULL;
}
if (m_hReadEvent)
{
CloseHandle(m_hReadEvent);
m_hReadEvent = NULL;
}
return TRUE;
}
BOOL CSharedMutex::Lock( LockLevel level /*= LockLevelRead*/, int nTimeOutMs /*= INFINITE*/, LPCTSTR szFile /*= NULL*/, int nLine /*= 0*/ )
{
assert(level!= LockLevelNone);
BOOL bResult = FALSE;
DWORD dwWaitResult = 0;
if (level == LockLevelRead)
{
//要读,保证没人在写
if (m_currentLevel != LockLevelRead)
{
dwWaitResult = WaitForSingleObject(m_hWriteEvent, nTimeOutMs);
if (dwWaitResult != WAIT_OBJECT_0)
{
bResult = FALSE;
}
else
{
EnterCriticalSection(&m_csStateChange);
//设置读信号为无信号状态
ResetEvent(m_hReadEvent);
//这是候写信号也是没信号的了
//我们虽然不用写,但是也不能让他有信号
m_currentLevel = level;
m_nReadingCount++;
bResult = TRUE;
#ifdef _DEBUG
_TrackOwner(szFile, nLine, level);
#endif // _DEBUG
LeaveCriticalSection(&m_csStateChange);
}
}
else
{
//有其他人在读,这里可以共享读
EnterCriticalSection(&m_csStateChange);
//设置读信号为无信号状态
ResetEvent(m_hReadEvent);
//我们虽然不用写,但是也不能让他有信号
ResetEvent(m_hWriteEvent);
m_currentLevel = level;
m_nReadingCount++;
bResult = TRUE;
#ifdef _DEBUG
_TrackOwner(szFile, nLine, level);
#endif // _DEBUG
LeaveCriticalSection(&m_csStateChange);
}
}
else if (level == LockLevelWrite)
{
//要写,保证没人写和没人读
dwWaitResult = WaitForSingleObject(m_hWriteEvent, nTimeOutMs);
if (dwWaitResult != WAIT_OBJECT_0)
{
bResult = FALSE;
}
else
{
//没人写但是有人读
dwWaitResult = WaitForSingleObject(m_hReadEvent, nTimeOutMs);
if (dwWaitResult != WAIT_OBJECT_0)
{
bResult = FALSE;
}
else
{
//没人写,没人读,设置写信号为无信号状态
//此时,读,写,都已经是无信号,不需要手工设置
EnterCriticalSection(&m_csStateChange);
bResult = FALSE;
m_currentLevel = level;
bResult = TRUE;
#ifdef _DEBUG
_TrackOwner(szFile, nLine, level);
#endif // _DEBUG
LeaveCriticalSection(&m_csStateChange);
}
}
}
else
{
assert("Invalid LockLevel" == NULL);
}
return bResult;
}
BOOL CSharedMutex::Unlock()
{
//这种写法,保证函数只有一个出口
EnterCriticalSection(&m_csStateChange);
BOOL bResult = FALSE;
DWORD dwWaitResult = 0;
//没锁住鼓捣啥啊
assert(m_currentLevel != LockLevelNone);
if (m_currentLevel == LockLevelRead)
{
//设置读写信号为有信号
SetEvent(m_hReadEvent);
m_nReadingCount--;
if (m_nReadingCount == 0)
{
m_currentLevel = LockLevelNone;
//保证没人读才给写
SetEvent(m_hWriteEvent);
}
}
else if (m_currentLevel == LockLevelWrite)
{
//设置读写信号为有信号
SetEvent(m_hReadEvent);
SetEvent(m_hWriteEvent);
m_currentLevel = LockLevelNone;
}
else
{
assert("Invalid LockLevel" == NULL);
}
#ifdef _DEBUG
int nThreadId = ::GetCurrentThreadId();
OwnerMap::iterator it = m_ownerMap.find(nThreadId);
if (it != m_ownerMap.end())
{
m_ownerMap.erase(it);
}
#endif
LeaveCriticalSection(&m_csStateChange);
return bResult;
}
#ifdef _DEBUG
void CSharedMutex::_TrackOwner(LPCTSTR szFile, int nLine, LockLevel level)
{
int nThreadId = GetCurrentThreadId();
CLockOwner owner(szFile, nLine, nThreadId, level);
m_ownerMap.insert(std::make_pair(nThreadId, owner));
}
#endif
CWriteLock::CWriteLock( CSharedMutex* pMutex )
{
m_pMutex = pMutex;
if (m_pMutex != NULL)
{
m_pMutex->Lock(LockLevelWrite);
}
}
CWriteLock::CWriteLock( CSharedMutex* pMutex, LPCTSTR szFile, int nLine )
{
m_pMutex = pMutex;
if (m_pMutex != NULL)
{
m_pMutex->Lock(LockLevelWrite, INFINITE, szFile, nLine);
}
}
CWriteLock::~CWriteLock()
{
Unlock();
}
BOOL CWriteLock::Unlock()
{
if (m_pMutex)
{
m_pMutex->Unlock();
m_pMutex = NULL;
}
return TRUE;
}
BOOL CWriteLock::Lock( LPCTSTR szFile, int nLine )
{
if (m_pMutex != NULL)
{
m_pMutex->Lock(LockLevelWrite, INFINITE, szFile, nLine);
}
return TRUE;
}
CReadLock::CReadLock( CSharedMutex* pMutex )
{
m_pMutex = pMutex;
if (m_pMutex != NULL)
{
m_pMutex->Lock(LockLevelRead);
}
}
CReadLock::CReadLock( CSharedMutex* pMutex, LPCTSTR szFile, int nLine )
{
m_pMutex = pMutex;
if (m_pMutex != NULL)
{
m_pMutex->Lock(LockLevelRead, INFINITE, szFile, nLine);
}
}
CReadLock::~CReadLock()
{
Unlock();
}
BOOL CReadLock::Unlock()
{
if (m_pMutex)
{
m_pMutex->Unlock();
m_pMutex = NULL;
}
return TRUE;
}
BOOL CReadLock::Lock( LPCTSTR szFile, int nLine )
{
if (m_pMutex != NULL)
{
m_pMutex->Lock(LockLevelRead, INFINITE, szFile, nLine);
}
return TRUE;
}
}
#pragma once
#include <Windows.h>
namespace cc
{
#ifdef _DEBUG
//#define READ_LOCK(readLock, mutex) cc::CReadLock readLock(mutex, _T(__FILE__), __LINE__)
// #define WRITE_LOCK(writeLock, mutex)\
// _FC_LOG("%s WRITE_LOCK_%d_%d BEGIN", __FUNCTION__, __LINE__, GetCurrentThreadId()); \
// cc::CWriteLock writeLock(mutex, _T(__FILE__), __LINE__); \
// _FC_LOG("%s WRITE_LOCK_%d_%d OK\r\n", __FUNCTION__, __LINE__, GetCurrentThreadId())
//
// #define READ_LOCK(readLock, mutex) \
// _FC_LOG("%s WRITE_LOCK_%d_%d BEGIN", __FUNCTION__, __LINE__, GetCurrentThreadId()); \
// cc::CReadLock readLock(mutex, _T(__FILE__), __LINE__); \
// _FC_LOG("%s WRITE_LOCK_%d_%d OK\r\n", __FUNCTION__, __LINE__, GetCurrentThreadId())
#define WRITE_LOCK(writeLock, mutex)\
cc::CWriteLock writeLock(mutex, _T(__FILE__), __LINE__);
#define READ_LOCK(readLock, mutex) \
cc::CReadLock readLock(mutex, _T(__FILE__), __LINE__); \
#else
#define WRITE_LOCK(writeLock, mutex) cc::CWriteLock writeLock(mutex)
#define READ_LOCK(readLock, mutex) cc::CReadLock readLock(mutex)
#endif
enum LockLevel
{
LockLevelNone,
LockLevelRead,
LockLevelWrite
};
#ifdef _DEBUG
class CLockOwner
{
public:
CLockOwner(LPCTSTR lpFile, int nLine, int nThreadId, LockLevel level)
{
m_strFile = lpFile;
m_nLine = nLine;
m_nThreadId = nThreadId;
m_level = level;
}
private:
CString m_strFile;
int m_nLine;
int m_nThreadId;
LockLevel m_level;
};
#endif
class CSharedMutex
{
public:
CSharedMutex(void);
~CSharedMutex(void);
BOOL Init();
BOOL Uninit();
BOOL Lock(LockLevel level = LockLevelRead, int nTimeOutMs = INFINITE, LPCTSTR szFile = NULL, int nLine = 0);
BOOL Unlock();
private:
CSharedMutex(const CSharedMutex&);
CSharedMutex& operator =(const CSharedMutex&);
#ifdef _DEBUG
void _TrackOwner(LPCTSTR szFile, int nLine, LockLevel level);
#endif
private:
HANDLE m_hWriteEvent;
HANDLE m_hReadEvent;
LockLevel m_currentLevel;
CRITICAL_SECTION m_csStateChange;
int m_nReadingCount;
#ifdef _DEBUG
typedef std::map<int, CLockOwner> OwnerMap;
OwnerMap m_ownerMap;
#endif
};
class CWriteLock
{
public:
CWriteLock(CSharedMutex* pMutex);
CWriteLock(CSharedMutex* pMutex, LPCTSTR szFile, int nLine);
~CWriteLock();
BOOL Lock(LPCTSTR szFile, int nLine);
BOOL Unlock();
private:
CSharedMutex* m_pMutex;
};
class CReadLock
{
public:
CReadLock(CSharedMutex* pMutex);
CReadLock(CSharedMutex* pMutex, LPCTSTR szFile, int nLine);
~CReadLock();
BOOL Lock(LPCTSTR szFile, int nLine);
BOOL Unlock();
private:
CSharedMutex* m_pMutex;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment