swmrg.c

来自「一本已经绝版的好书」· C语言 代码 · 共 228 行

C
228
字号
/************************************************************
Module name: SWMRG.C
Notices: Copyright (c) 1995-1997 Jeffrey Richter
************************************************************/


#include "..\CmnHdr.H"                  /* See Appendix C. */
#include <windows.h>
#include <string.h>
#include <tchar.h>
#include "SWMRG.H"		      // The header file


/////////////////////////////////////////////////////////////


static LPCTSTR ConstructObjName (
	LPCTSTR lpszPrefix, LPCTSTR lpszSuffix, 
	LPTSTR lpszFullName, size_t cbFullName, PBOOL fOk) {
	*fOk = TRUE;	// Assume success.

	if (lpszSuffix == NULL)
		return(NULL);

	if ((_tcslen(lpszPrefix) + _tcslen(lpszSuffix)) >= 
		cbFullName) {
		// If the strings will overflow the buffer,
		// indicate an error.
		*fOk = FALSE;
		return(NULL);
	}

	_tcscpy(lpszFullName, lpszPrefix);
	_tcscat(lpszFullName, lpszSuffix);
	return(lpszFullName);
}


/////////////////////////////////////////////////////////////


BOOL SWMRGInitialize(PSWMRG pSWMRG, LPCTSTR lpszName) {
	TCHAR szFullObjName[100];
	LPCTSTR lpszObjName;
	BOOL fOk;

	// Initialize all data members to NULL so that we can
	// accurately check whether an error has occurred.
	pSWMRG->hMutexNoWriter = NULL;
	pSWMRG->hEventNoReaders = NULL;
	pSWMRG->hSemNumReaders = NULL;

	// This mutex guards access to the other objects
	// managed by this data structure and also indicates 
	// whether there are any writer threads writing.
	// Initially no thread owns the mutex.
	lpszObjName = ConstructObjName(
		__TEXT("SWMRGMutexNoWriter"), lpszName,
		szFullObjName, chDIMOF(szFullObjName), &fOk);
	if (fOk)		
		pSWMRG->hMutexNoWriter =
			CreateMutex(NULL, FALSE, lpszObjName);

	// Create the manual-reset event that is signalled when 
	// no reader threads are reading.
	// Initially no reader threads are reading.
	lpszObjName = ConstructObjName(
		__TEXT("SWMRGEventNoReaders"), lpszName,
		szFullObjName, chDIMOF(szFullObjName), &fOk);
	if (fOk)
		pSWMRG->hEventNoReaders =
			CreateEvent(NULL, TRUE, TRUE, lpszObjName);

	// Initialize the variable that indicates the number of 
	// reader threads that are reading.
	// Initially no reader threads are reading.
	lpszObjName = ConstructObjName(
		__TEXT("SWMRGSemNumReaders"), lpszName,
		szFullObjName, chDIMOF(szFullObjName), &fOk);
	if (fOk)
		pSWMRG->hSemNumReaders = 
			CreateSemaphore(NULL, 0, 0x7FFFFFFF, lpszObjName);


	if ((NULL == pSWMRG->hMutexNoWriter)   || 
		 (NULL == pSWMRG->hEventNoReaders)	||
		 (NULL == pSWMRG->hSemNumReaders)) {
		// If a synchronization object could not be created,
		// destroy any created objects and return failure.
		SWMRGDelete(pSWMRG);
		fOk = FALSE;
	} else {
		fOk = TRUE;
	}

	// Return TRUE upon success, FALSE upon failure.
	return(fOk);
}


/////////////////////////////////////////////////////////////


void SWMRGDelete(PSWMRG pSWMRG) {

	// Destroy any synchronization objects that were 
	// successfully created.
	if (NULL != pSWMRG->hMutexNoWriter)
		CloseHandle(pSWMRG->hMutexNoWriter);

	if (NULL != pSWMRG->hEventNoReaders)
		CloseHandle(pSWMRG->hEventNoReaders);

	if (NULL != pSWMRG->hSemNumReaders)
		CloseHandle(pSWMRG->hSemNumReaders);
}


/////////////////////////////////////////////////////////////


DWORD SWMRGWaitToWrite(PSWMRG pSWMRG, DWORD dwTimeout) {
	DWORD dw; 
	HANDLE aHandles[2];

   // We can write if the following are true:
   // 1. The mutex guard is available and
   //    no other threads are writing.
   // 2. No threads are reading.
	aHandles[0] = pSWMRG->hMutexNoWriter;
	aHandles[1] = pSWMRG->hEventNoReaders;
   dw = WaitForMultipleObjects(2, aHandles, TRUE, dwTimeout);

	if (dw != WAIT_TIMEOUT) {
		// This thread can write to the shared data.

		// Because a writer thread is writing, the mutex 
      // should not be released. This stops other 
      // writers and readers.
	}

	return(dw);
}


/////////////////////////////////////////////////////////////


void SWMRGDoneWriting(PSWMRG pSWMRG) {
   // Presumably, a writer thread calling this function has
   // successfully called WaitToWrite. This means that we
   // do not have to wait on any synchronization objects 
   // here because the writer already owns the mutex.

	// Allow other writer/reader threads to use
	// the SWMRG synchronization object.
	ReleaseMutex(pSWMRG->hMutexNoWriter);
}


/////////////////////////////////////////////////////////////


DWORD SWMRGWaitToRead(PSWMRG pSWMRG, DWORD dwTimeout) {
	DWORD dw; 
	LONG lPreviousCount;

   // We can read if the mutex guard is available
   // and no threads are writing.
   dw = WaitForSingleObject(pSWMRG->hMutexNoWriter, dwTimeout);

	if (dw != WAIT_TIMEOUT) {
		// This thread can read from the shared data.

		// Increment the number of reader threads.
		ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lPreviousCount);
		if (lPreviousCount == 0) {
			// If this is the first reader thread, 
			// set our event to reflect this.
			ResetEvent(pSWMRG->hEventNoReaders);
		}

		// Allow other writer/reader threads to use
		// the SWMRG synchronization object.
		ReleaseMutex(pSWMRG->hMutexNoWriter);
	}

	return(dw);
}


/////////////////////////////////////////////////////////////


void SWMRGDoneReading (PSWMRG pSWMRG) {
	HANDLE aHandles[2];
	LONG lNumReaders;

	// We can stop reading if the mutex guard is available,
	// but when we stop reading we must also decrement the
	// number of reader threads.
	aHandles[0] = pSWMRG->hMutexNoWriter;
	aHandles[1] = pSWMRG->hSemNumReaders;
	WaitForMultipleObjects(2, aHandles, TRUE, INFINITE);

	// Get the remaining number of readers by releasing the
	// semaphore and then restoring the count by immediately
	// performing a wait.
	ReleaseSemaphore(pSWMRG->hSemNumReaders, 1,
		&lNumReaders);
	WaitForSingleObject(pSWMRG->hSemNumReaders, INFINITE);

	// If there are no remaining readers, 
   // set the event to relect this.
	if (lNumReaders == 0) {
      // If there are no reader threads, 
		// set our event to reflect this.
      SetEvent(pSWMRG->hEventNoReaders);
   }

	// Allow other writer/reader threads to use
	// the SWMRG synchronization object.
	ReleaseMutex(pSWMRG->hMutexNoWriter);
}


//////////////////////// End Of File ////////////////////////

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?