Last active
October 28, 2020 07:05
-
-
Save ccnyou/d2ce9c08c19ae3da2a3cd700dd293e2e to your computer and use it in GitHub Desktop.
大学时候使用C++在Windows环境下实现的读写锁
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CXxx | |
{ | |
//other code... | |
cc::CSharedMutex m_xxxMutex; // 声明要互斥变量 | |
} | |
CXxx::SomeMethod() | |
{ | |
{ //限定锁的作用域 | |
//readLock 是变量名,可以随意指定 | |
//READ_LOCK(readLock, &m_xxxMutex); | |
WRITE_LOCK(writeLock, &m_xxxMutex); | |
//使用互斥资源 | |
//... | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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