写优先读写锁,读效率比 WINDOWS 的 SRWLOCK 慢一倍左右,百万级读锁要156ms

#pragma once

/**************************************************
写优先读写锁
	读效率比 WINDOWS 的 SRWLOCK 慢一倍左右,百万级读锁要156ms(78ms)
	写效率比 WINDOWS 的 SRWLOCK 慢 N 倍,百万级写锁要1516ms(62ms)
	CKSRWLock		读写锁实现
	CAutoLockRead	读锁的自动化(RAII 机制)
	CAutoLockWrite	写锁的自动化(RAII 机制)

使用方法(代码示例):

	CKSRWLock ksrwLock;

	void Read()
	{
		CAutoLockRead lock(ksrwLock);
		// TODO:读的代码
	}

	void Write()
	{
		CAutoLockWrite lock(ksrwLock);
		// TODO:写的代码
	}

**************************************************/
#include 

class CKSRWLock
{
public:
	void LockWrite()
	{
		// 写等待的计数变量
		assert(m_refWriteWaitCount >= 0);
		InterlockedIncrement(&m_refWriteWaitCount);
		// 临界区
		EnterCriticalSection(&m_csWrite);
		// 不可读
		ResetEvent(m_eventReadEnable);
		// 互斥
		InterlockedExchangeAdd(&m_refCount, -m_clMAX_READ);
		// 等待所有读完成
		while (m_refCount < 0);
	}
	void UnlockWrite()
	{
		// 互斥
		LONG init = InterlockedExchangeAdd(&m_refCount, m_clMAX_READ);
		
		// 写等待的计数变量
		LONG value = InterlockedDecrement(&m_refWriteWaitCount);
		assert(value >= 0);
		
		// 可读
		SetEvent(m_eventReadEnable);
		// 临界区
		LeaveCriticalSection(&m_csWrite);
	}

	// 返回并发读的线程数
	LONG LockRead()
	{
		// 优化,使用一个写等待的计数变量,避免直接 Wait
		if (0 == m_refWriteWaitCount)
		{
			// 互斥
			LONG iResult = InterlockedDecrement(&m_refCount);
			if (iResult > 0)
			{
				// Lock : n -> (n - 1)
				return m_clMAX_READ - iResult;
			}
			else
			{
				InterlockedIncrement(&m_refCount);
			}
		}
		// 基本流程
		while (true)
		{
			// 进入内核等待
			if (WAIT_TIMEOUT == WaitForSingleObject(m_eventReadEnable, INFINITE))
			{
				return 0;
			}
			if (0 == m_refWriteWaitCount)
			{
				// 互斥
				LONG iResult = InterlockedDecrement(&m_refCount);
				if (iResult > 0)
				{
					// Lock : n -> (n - 1)
					return m_clMAX_READ - iResult;
				}
				else
				{
					InterlockedIncrement(&m_refCount);
				}
			}
		}
	}

	// 返回并发读的线程数(0 表示 Lock 失败)
	LONG TryLockRead(DWORD dwTick = 0)
	{
		// 优化,使用一个写等待的计数变量,避免直接 Wait
		if (0 == m_refWriteWaitCount)
		{
			// 互斥
			LONG iResult = InterlockedDecrement(&m_refCount);
			if (iResult > 0)
			{
				// Lock : n -> (n - 1)
				return m_clMAX_READ - iResult;
				}
				else
				{
					InterlockedIncrement(&m_refCount);
				}
			}
		if (0 == dwTick) return 0;
		// 基本流程
		// 进入内核等待
		if (WAIT_TIMEOUT == WaitForSingleObject(m_eventReadEnable, dwTick))
		{
			return 0;
		}
		if (0 == m_refWriteWaitCount)
		{
			// 互斥
			LONG iResult = InterlockedDecrement(&m_refCount);
			if (iResult > 0)
			{
				// Lock : n -> (n - 1)
				return m_clMAX_READ - iResult;
			}
			else
			{
				InterlockedIncrement(&m_refCount);
		}
	}
		return 0;
	}

	void UnlockRead()
	{
		// 互斥
		InterlockedIncrement(&m_refCount);
	}

public:
	CKSRWLock(void):m_refCount(m_clMAX_READ),m_refWriteWaitCount(0)
	{
		InitializeCriticalSection(&m_csWrite);
		m_eventReadEnable = ::CreateEvent(NULL, TRUE, TRUE, NULL);
		SetEvent(m_eventReadEnable);
	}
	virtual ~CKSRWLock(void)
	{
		try
		{
			DeleteCriticalSection(&m_csWrite);
			CloseHandle(m_eventReadEnable);
		}
		catch(...)
		{
		}
	}

protected:
	// 最大不会超过 m_clMAX_READ 个并发读
	static const LONG	m_clMAX_READ = 1000000;
	// m_refCount: using interlocked funtions to access
	// 100000000		- free
	// 0				- one thread is writing
	// 100000000 - n	- n threads are reading
	volatile LONG		m_refCount;
	// n	- n threads are waiting to wirte
	volatile LONG		m_refWriteWaitCount;	
	// once a thread to write
	CRITICAL_SECTION	m_csWrite;
	// wait for writing complete
	HANDLE				m_eventReadEnable;
};


class CAutoLockWrite  
{
public:
	CAutoLockWrite(CKSRWLock& cs, BOOL bLock = TRUE, LPCTSTR szDebugMsg = NULL):m_cs(cs), m_bLeaved(TRUE), m_strDebugMsg(szDebugMsg)
	{
		if (bLock)
		{
			Lock();
		}
	}
	void Lock()
	{
		if (m_bLeaved)
	{
		m_cs.LockWrite();
			m_bLeaved = FALSE;
			if (!m_strDebugMsg.empty())
			{
				// CLOG::Research(_T("WLOCK: %s Lock<<<<<<<<<<<<<<<<"), m_strDebugMsg.c_str());
			}
		}
	}
	// sometimes we need release it as soon as possible, so just call Leave().
	void Unlock()
	{
		if (!m_bLeaved)
		{
			if (!m_strDebugMsg.empty())
			{
				// CLOG::Research(_T("WLOCK: %s UnLock>>>>>>>>>>>>>>>"), m_strDebugMsg.c_str());
			}
			m_cs.UnlockWrite();
			m_bLeaved = TRUE;
		}
	}
	// auto-release
	virtual ~CAutoLockWrite()
	{
		try
		{
			Unlock();
		}
		catch(...)
		{
		}
	}

protected:
	// members
	CKSRWLock& m_cs;
	BOOL  m_bLeaved;
	tstring		m_strDebugMsg;

private:
	// no copy or assignment
	CAutoLockWrite(const CAutoLockWrite&);
	CAutoLockWrite& operator=(const CAutoLockWrite&);
};

class CAutoLockRead  
{
public:
	CAutoLockRead(CKSRWLock& cs, BOOL bLock = TRUE):m_cs(cs), m_bLeaved(TRUE),m_readThreadCount(0)
	{
		if (bLock)
		{
			Lock();
		}
	}
	BOOL TryLock(DWORD dwTick = 0)
	{
		assert(m_bLeaved);
		if (m_bLeaved)
		{
			m_readThreadCount = m_cs.TryLockRead(dwTick);
			if (0 != m_readThreadCount)
			{
				m_bLeaved = FALSE;
				return TRUE;
			}
		}
		return FALSE;
	}
	void Lock()
	{
		assert(m_bLeaved);
		if (m_bLeaved)
	{
		m_readThreadCount = m_cs.LockRead();
			m_bLeaved = FALSE;
		}
	}
	// sometimes we need release it as soon as possible, so just call Leave().
	void Unlock()
	{
		if (!m_bLeaved)
		{
			m_cs.UnlockRead();
			m_bLeaved = TRUE;
		}
	}
	LONG GetReadCount()const {return m_readThreadCount;}
	// auto-release
	virtual ~CAutoLockRead()
	{
		try
		{
			Unlock();
		}
		catch(...)
		{
		}
	}

protected:
	// members
	CKSRWLock& m_cs;
	BOOL m_bLeaved;
	LONG m_readThreadCount;

private:
	// no copy or assignment
	CAutoLockRead(const CAutoLockRead&);
	CAutoLockRead& operator=(const CAutoLockRead&);
};


 

你可能感兴趣的:(并发)