臨界領域読み出し操作クラスCRWcriticalSection

2858 ワード

class CRWCriticalSection  
	{
	public:
		explicit CRWCriticalSection();
		~CRWCriticalSection();

	public:
		BOOL LockReader(unsigned int nTimeOut = INFINITE);
		void UnlockReader();
		BOOL LockWriter(unsigned int nTimeOut = INFINITE);
		void UnlockWriter(); 
	private:
	       /*****/
		HANDLE m_hNobodyIsReading;
		HANDLE m_hWritingMutex;
		CRITICAL_SECTION m_csReading;
		unsigned int m_nReaders;

		CRWCriticalSection(const CRWCriticalSection& cs);
		CRWCriticalSection& operator=(const CRWCriticalSection& cs);
	};
CRWCriticalSection::CRWCriticalSection()
	{
		// Create the flag that indicates if somebody is reading the object
		//     initially, nobody is...
		m_hNobodyIsReading = CreateEvent(NULL, TRUE, TRUE, NULL);

		// Create a mutex indicating who is writing (only one)
		m_hWritingMutex = CreateMutex(NULL, FALSE, NULL);

		assert(m_hNobodyIsReading && m_hWritingMutex);

		// Create the critical section for maintaining the number of readers
		//   it should not delay much (so no need to analyse for deadlocks)
		InitializeCriticalSection(&m_csReading);

		m_nReaders = 0;
	}

	CRWCriticalSection::~CRWCriticalSection()
	{
		CloseHandle(m_hNobodyIsReading);
		CloseHandle(m_hWritingMutex);
		DeleteCriticalSection(&m_csReading);

		assert(m_nReaders == 0);
	}

	BOOL CRWCriticalSection::LockReader(unsigned int nTimeout)
	{
		// We make sure that nobody is writing
		if (WaitForSingleObject(m_hWritingMutex, nTimeout) != WAIT_OBJECT_0)
			return FALSE;

		// We need a critical section to update the number of readers
		EnterCriticalSection(&m_csReading);
		{
			m_nReaders++;
			if (m_nReaders == 1)
			{
				// We must indicate that there are some readers
				ResetEvent(m_hNobodyIsReading);
			}
		}
		LeaveCriticalSection(&m_csReading);

		// I release the mutex for writing that I do not need
		ReleaseMutex(m_hWritingMutex);

		return TRUE;
	}


	void CRWCriticalSection::UnlockReader()
	{
		// We need a critical section to update the number of readers
		EnterCriticalSection(&m_csReading);
		{
			m_nReaders--;
			if (m_nReaders == 0)
			{
				// We indicate that there are no more readers
				SetEvent(m_hNobodyIsReading);
			}
		}
		LeaveCriticalSection(&m_csReading);
	}

	BOOL CRWCriticalSection::LockWriter(unsigned int nTimeout)
	{
		// Only one writer at a time
		if (WaitForSingleObject(m_hWritingMutex,nTimeout) != WAIT_OBJECT_0)
			return FALSE;

		// Wait for all readers to leave
		if (WaitForSingleObject(m_hNobodyIsReading,nTimeout) != WAIT_OBJECT_0)
		{
			// We have waited too long, so we have to set the "Writing" mutex
			ReleaseMutex(m_hWritingMutex);
			return FALSE;
		}

		return TRUE;
	}


	void CRWCriticalSection::UnlockWriter()
	{
		// Let other readers and writers in
		ReleaseMutex(m_hWritingMutex);
	}