613 lines
12 KiB
C
613 lines
12 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1999-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
locks.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Various C++ class for sync. object
|
||
|
|
||
|
Author:
|
||
|
|
||
|
HueiWang 2/17/2000
|
||
|
|
||
|
--*/
|
||
|
#ifndef __LOCKS_H
|
||
|
#define __LOCKS_H
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <winbase.h>
|
||
|
#include "assert.h"
|
||
|
|
||
|
#define ARRAY_COUNT(a) sizeof(a) / sizeof(a[0])
|
||
|
|
||
|
//
|
||
|
// Semaphore template
|
||
|
//
|
||
|
template <int init_count, int max_count>
|
||
|
class CTSemaphore
|
||
|
{
|
||
|
private:
|
||
|
HANDLE m_semaphore;
|
||
|
|
||
|
public:
|
||
|
CTSemaphore() : m_semaphore(NULL)
|
||
|
{
|
||
|
m_semaphore = CreateSemaphore(
|
||
|
NULL,
|
||
|
init_count,
|
||
|
max_count,
|
||
|
NULL
|
||
|
);
|
||
|
assert(m_semaphore != NULL);
|
||
|
}
|
||
|
|
||
|
~CTSemaphore()
|
||
|
{
|
||
|
if(m_semaphore)
|
||
|
{
|
||
|
CloseHandle(m_semaphore);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
Acquire(
|
||
|
int WaitTime=INFINITE,
|
||
|
BOOL bAlertable=FALSE
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return WaitForSingleObjectEx(
|
||
|
m_semaphore,
|
||
|
WaitTime,
|
||
|
bAlertable
|
||
|
);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
AcquireEx(
|
||
|
HANDLE hHandle,
|
||
|
int dwWaitTime=INFINITE,
|
||
|
BOOL bAlertable=FALSE
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL bSuccess = TRUE;
|
||
|
DWORD dwStatus;
|
||
|
HANDLE hHandles[] = {m_semaphore, hHandle};
|
||
|
|
||
|
if(hHandle == NULL || hHandle == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
bSuccess = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwStatus = WaitForMultipleObjectsEx(
|
||
|
sizeof(hHandles)/sizeof(hHandles[0]),
|
||
|
hHandles,
|
||
|
FALSE,
|
||
|
dwWaitTime,
|
||
|
bAlertable
|
||
|
);
|
||
|
|
||
|
if(dwStatus != WAIT_OBJECT_0)
|
||
|
{
|
||
|
bSuccess = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL Release(long count=1)
|
||
|
{
|
||
|
return ReleaseSemaphore(m_semaphore, count, NULL);
|
||
|
}
|
||
|
|
||
|
BOOL IsGood()
|
||
|
{
|
||
|
return m_semaphore != NULL;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// Critical section C++ class.
|
||
|
//
|
||
|
class CCriticalSection
|
||
|
{
|
||
|
|
||
|
CRITICAL_SECTION m_CS;
|
||
|
BOOL m_bGood;
|
||
|
|
||
|
public:
|
||
|
CCriticalSection(
|
||
|
DWORD dwSpinCount = 4000 // see InitializeCriticalSection...
|
||
|
) : m_bGood(TRUE)
|
||
|
{
|
||
|
|
||
|
__try {
|
||
|
InitializeCriticalSectionAndSpinCount(&m_CS, dwSpinCount);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
SetLastError(GetExceptionCode());
|
||
|
m_bGood = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~CCriticalSection()
|
||
|
{
|
||
|
if(IsGood() == TRUE)
|
||
|
{
|
||
|
DeleteCriticalSection(&m_CS);
|
||
|
m_bGood = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsGood()
|
||
|
{
|
||
|
return m_bGood;
|
||
|
}
|
||
|
|
||
|
void Lock()
|
||
|
{
|
||
|
EnterCriticalSection(&m_CS);
|
||
|
}
|
||
|
|
||
|
void UnLock()
|
||
|
{
|
||
|
LeaveCriticalSection(&m_CS);
|
||
|
}
|
||
|
|
||
|
BOOL TryLock()
|
||
|
{
|
||
|
return TryEnterCriticalSection(&m_CS);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Critical section locker, this class lock the critical section
|
||
|
// at object constructor and release object at destructor, purpose is to
|
||
|
// prevent forgoting to release a critical section.
|
||
|
//
|
||
|
// usage is
|
||
|
//
|
||
|
// void
|
||
|
// Foo( void )
|
||
|
// {
|
||
|
// CCriticalSectionLocker l( <some CCriticalSection instance> )
|
||
|
//
|
||
|
// }
|
||
|
//
|
||
|
//
|
||
|
class CCriticalSectionLocker
|
||
|
{
|
||
|
|
||
|
private:
|
||
|
CCriticalSection& m_cs;
|
||
|
|
||
|
public:
|
||
|
CCriticalSectionLocker( CCriticalSection& m ) : m_cs(m)
|
||
|
{
|
||
|
m.Lock();
|
||
|
}
|
||
|
|
||
|
~CCriticalSectionLocker()
|
||
|
{
|
||
|
m_cs.UnLock();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Safe counter class.
|
||
|
//
|
||
|
class CSafeCounter
|
||
|
{
|
||
|
|
||
|
private:
|
||
|
|
||
|
long m_Counter;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CSafeCounter(
|
||
|
long init_value=0
|
||
|
) :
|
||
|
m_Counter(init_value)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
}
|
||
|
|
||
|
~CSafeCounter()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
operator+=(long dwValue)
|
||
|
{
|
||
|
long dwNewValue;
|
||
|
|
||
|
dwNewValue = InterlockedExchangeAdd(
|
||
|
&m_Counter,
|
||
|
dwValue
|
||
|
);
|
||
|
return dwNewValue += dwValue;
|
||
|
}
|
||
|
|
||
|
operator-=(long dwValue)
|
||
|
{
|
||
|
long dwNewValue;
|
||
|
|
||
|
dwNewValue = InterlockedExchangeAdd(
|
||
|
&m_Counter,
|
||
|
-dwValue
|
||
|
);
|
||
|
return dwNewValue -= dwValue;
|
||
|
}
|
||
|
|
||
|
operator++()
|
||
|
{
|
||
|
return InterlockedIncrement(&m_Counter);
|
||
|
}
|
||
|
|
||
|
operator++(int)
|
||
|
{
|
||
|
long lValue;
|
||
|
|
||
|
lValue = InterlockedIncrement(&m_Counter);
|
||
|
return --lValue;
|
||
|
}
|
||
|
|
||
|
operator--()
|
||
|
{
|
||
|
return InterlockedDecrement(&m_Counter);
|
||
|
}
|
||
|
|
||
|
operator--(int)
|
||
|
{
|
||
|
long lValue;
|
||
|
|
||
|
lValue = InterlockedDecrement(&m_Counter);
|
||
|
return ++lValue;
|
||
|
}
|
||
|
|
||
|
operator long()
|
||
|
{
|
||
|
return InterlockedExchange(&m_Counter, m_Counter);
|
||
|
}
|
||
|
|
||
|
operator=(const long dwValue)
|
||
|
{
|
||
|
InterlockedExchange(&m_Counter, dwValue);
|
||
|
return dwValue;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Reader/Writer lock, modified from MSDN
|
||
|
//
|
||
|
|
||
|
typedef enum {
|
||
|
WRITER_LOCK,
|
||
|
READER_LOCK,
|
||
|
NO_LOCK
|
||
|
} RWLOCK_TYPE;
|
||
|
|
||
|
|
||
|
class CRWLock
|
||
|
{
|
||
|
private:
|
||
|
HANDLE hMutex;
|
||
|
HANDLE hWriterMutex;
|
||
|
HANDLE hReaderEvent;
|
||
|
long iReadCount;
|
||
|
long iWriteCount;
|
||
|
|
||
|
long iReadEntry;
|
||
|
long iWriteEntry;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CRWLock()
|
||
|
{
|
||
|
BOOL bSuccess=Init();
|
||
|
assert(bSuccess == TRUE);
|
||
|
}
|
||
|
|
||
|
~CRWLock()
|
||
|
{
|
||
|
Cleanup();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
BOOL
|
||
|
Init()
|
||
|
{
|
||
|
hReaderEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
|
||
|
hMutex = CreateEvent(NULL,FALSE,TRUE,NULL);
|
||
|
hWriterMutex = CreateMutex(NULL,FALSE,NULL);
|
||
|
if(!hReaderEvent || !hMutex || !hWriterMutex)
|
||
|
return FALSE;
|
||
|
|
||
|
iReadCount = -1;
|
||
|
iWriteCount = -1;
|
||
|
iReadEntry = 0;
|
||
|
iWriteEntry = 0;
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
void
|
||
|
Cleanup()
|
||
|
{
|
||
|
CloseHandle(hReaderEvent);
|
||
|
CloseHandle(hMutex);
|
||
|
CloseHandle(hWriterMutex);
|
||
|
|
||
|
iReadCount = -1;
|
||
|
iWriteCount = -1;
|
||
|
iReadEntry = 0;
|
||
|
iWriteEntry = 0;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
void
|
||
|
Acquire(
|
||
|
RWLOCK_TYPE lockType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
++*/
|
||
|
{
|
||
|
if (lockType == WRITER_LOCK)
|
||
|
{
|
||
|
InterlockedIncrement(&iWriteCount);
|
||
|
WaitForSingleObject(hWriterMutex,INFINITE);
|
||
|
WaitForSingleObject(hMutex, INFINITE);
|
||
|
|
||
|
assert(InterlockedIncrement(&iWriteEntry) == 1);
|
||
|
assert(InterlockedExchange(&iReadEntry, iReadEntry) == 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (InterlockedIncrement(&iReadCount) == 0)
|
||
|
{
|
||
|
WaitForSingleObject(hMutex, INFINITE);
|
||
|
SetEvent(hReaderEvent);
|
||
|
}
|
||
|
|
||
|
WaitForSingleObject(hReaderEvent,INFINITE);
|
||
|
InterlockedIncrement(&iReadEntry);
|
||
|
assert(InterlockedExchange(&iWriteEntry, iWriteEntry) == 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------
|
||
|
void
|
||
|
Release(
|
||
|
RWLOCK_TYPE lockType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
++*/
|
||
|
{
|
||
|
if (lockType == WRITER_LOCK)
|
||
|
{
|
||
|
InterlockedDecrement(&iWriteEntry);
|
||
|
InterlockedDecrement(&iWriteCount);
|
||
|
SetEvent(hMutex);
|
||
|
ReleaseMutex(hWriterMutex);
|
||
|
}
|
||
|
else if(lockType == READER_LOCK)
|
||
|
{
|
||
|
InterlockedDecrement(&iReadEntry);
|
||
|
if (InterlockedDecrement(&iReadCount) < 0)
|
||
|
{
|
||
|
ResetEvent(hReaderEvent);
|
||
|
SetEvent(hMutex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long GetReadCount()
|
||
|
{
|
||
|
return iReadCount+1;
|
||
|
}
|
||
|
|
||
|
long GetWriteCount()
|
||
|
{
|
||
|
return iWriteCount+1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
class CCMutex
|
||
|
{
|
||
|
HANDLE hMutex;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CCMutex() : hMutex(NULL) {
|
||
|
hMutex=CreateMutex(NULL, FALSE, NULL);
|
||
|
}
|
||
|
|
||
|
~CCMutex() {
|
||
|
CloseHandle(hMutex);
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
Lock(
|
||
|
DWORD dwWaitTime=INFINITE,
|
||
|
BOOL bAlertable=FALSE
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return WaitForSingleObjectEx(
|
||
|
hMutex,
|
||
|
dwWaitTime,
|
||
|
bAlertable
|
||
|
);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Unlock()
|
||
|
{
|
||
|
return ReleaseMutex(hMutex);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------------------
|
||
|
|
||
|
class CCEvent
|
||
|
{
|
||
|
|
||
|
BOOL bManual;
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CCEvent(
|
||
|
BOOL bManual,
|
||
|
BOOL bInitState
|
||
|
) :
|
||
|
hEvent(NULL),
|
||
|
bManual(bManual)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
hEvent=CreateEvent(
|
||
|
NULL,
|
||
|
bManual,
|
||
|
bInitState,
|
||
|
NULL
|
||
|
);
|
||
|
}
|
||
|
|
||
|
~CCEvent()
|
||
|
{
|
||
|
if( NULL != hEvent )
|
||
|
{
|
||
|
CloseHandle(hEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
MsgLock(
|
||
|
DWORD dwWaitTime = INFINITE
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HANDLE wait_event[1] = {hEvent};
|
||
|
DWORD result ;
|
||
|
MSG msg ;
|
||
|
|
||
|
// The message loop lasts until we get a WM_QUIT message,
|
||
|
// upon which we shall return from the function.
|
||
|
while (TRUE)
|
||
|
{
|
||
|
// block-local variable
|
||
|
|
||
|
// Read all of the messages in this next loop,
|
||
|
// removing each message as we read it.
|
||
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||
|
{
|
||
|
// If it's a quit message, we're out of here.
|
||
|
if (msg.message == WM_QUIT)
|
||
|
{
|
||
|
return WAIT_ABANDONED;
|
||
|
}
|
||
|
|
||
|
// Otherwise, dispatch the message.
|
||
|
DispatchMessage(&msg);
|
||
|
} // End of PeekMessage while loop.
|
||
|
|
||
|
// Wait for any message sent or posted to this queue
|
||
|
// or for one of the passed handles be set to signaled.
|
||
|
result = MsgWaitForMultipleObjects(
|
||
|
1,
|
||
|
wait_event,
|
||
|
TRUE,
|
||
|
dwWaitTime,
|
||
|
QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_ALLEVENTS
|
||
|
);
|
||
|
|
||
|
// The result tells us the type of event we have.
|
||
|
if (result == WAIT_OBJECT_0 + 1)
|
||
|
{
|
||
|
// New messages have arrived.
|
||
|
// Continue to the top of the always while loop to
|
||
|
// dispatch them and resume waiting.
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
} // End of else clause.
|
||
|
} // End of the always while loop.
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
Lock(
|
||
|
DWORD dwWaitTime=INFINITE,
|
||
|
BOOL bAlertable=FALSE
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return WaitForSingleObjectEx(
|
||
|
hEvent,
|
||
|
dwWaitTime,
|
||
|
bAlertable
|
||
|
);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
SetEvent()
|
||
|
{
|
||
|
return ::SetEvent(hEvent);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ResetEvent()
|
||
|
{
|
||
|
return ::ResetEvent(hEvent);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
PulseEvent()
|
||
|
{
|
||
|
return ::PulseEvent(hEvent);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsManual()
|
||
|
{
|
||
|
return bManual;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif
|