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 + -
显示快捷键?