334 lines
8 KiB
C++
334 lines
8 KiB
C++
#ifndef _INC_CSCVIEW_THDSYNC_H
|
|
#define _INC_CSCVIEW_THDSYNC_H
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* File: thdsync.h
|
|
|
|
Description: Contains classes for managing thread synchronization in
|
|
Win32 programs. Most of the work is to provide automatic unlocking
|
|
of synchronization primities on object destruction. The work on
|
|
monitors and condition variables is strongly patterned after
|
|
work in "Multithreaded Programming with Windows NT" by Pham and Garg.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
09/22/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#ifndef _WINDOWS_
|
|
# include <windows.h>
|
|
#endif
|
|
#ifndef _INC_DSKQUOTA_DEBUG_H
|
|
# include "debug.h"
|
|
#endif
|
|
|
|
class CCriticalSection
|
|
{
|
|
public:
|
|
CCriticalSection(void)
|
|
{ InitializeCriticalSection(&m_cs); }
|
|
~CCriticalSection(void)
|
|
{ DeleteCriticalSection(&m_cs); }
|
|
|
|
void Enter(void)
|
|
{ EnterCriticalSection(&m_cs); }
|
|
|
|
void Leave(void)
|
|
{ LeaveCriticalSection(&m_cs); }
|
|
|
|
operator CRITICAL_SECTION& ()
|
|
{ return m_cs; }
|
|
|
|
private:
|
|
CRITICAL_SECTION m_cs;
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CCriticalSection(const CCriticalSection& rhs);
|
|
CCriticalSection& operator = (const CCriticalSection& rhs);
|
|
};
|
|
|
|
|
|
class CWin32SyncObj
|
|
{
|
|
public:
|
|
explicit CWin32SyncObj(HANDLE handle)
|
|
: m_handle(handle) { }
|
|
virtual ~CWin32SyncObj(void)
|
|
{ if (NULL != m_handle) CloseHandle(m_handle); }
|
|
|
|
HANDLE Handle(void)
|
|
{ return m_handle; }
|
|
|
|
protected:
|
|
HANDLE m_handle;
|
|
};
|
|
|
|
|
|
class CSemaphore : public CWin32SyncObj
|
|
{
|
|
public:
|
|
explicit CSemaphore(DWORD dwInitialCount = 0, DWORD dwMaxCount = 1);
|
|
~CSemaphore(void) { };
|
|
|
|
DWORD Wait(DWORD dwTimeout = INFINITE)
|
|
{ return WaitForSingleObject(m_handle, dwTimeout); }
|
|
void Release(DWORD dwReleaseCount = 1)
|
|
{ ReleaseSemaphore(m_handle, dwReleaseCount, NULL); }
|
|
|
|
private:
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CSemaphore(const CSemaphore& rhs);
|
|
CSemaphore& operator = (const CSemaphore& rhs);
|
|
};
|
|
|
|
|
|
class CSemaphoreList
|
|
{
|
|
public:
|
|
CSemaphoreList(void)
|
|
: m_pFirst(NULL),
|
|
m_pLast(NULL) { }
|
|
|
|
~CSemaphoreList(void);
|
|
|
|
void Append(CSemaphore *pSem);
|
|
void Prepend(CSemaphore *pSem);
|
|
CSemaphore *Head(void);
|
|
bool bEmpty(void)
|
|
{ return (NULL == m_pFirst); }
|
|
void Dump(void);
|
|
|
|
private:
|
|
class Item
|
|
{
|
|
public:
|
|
Item(CSemaphore *pSem, Item *pNext = NULL)
|
|
: m_pSem(pSem), m_pNext(pNext) { }
|
|
|
|
CSemaphore *m_pSem;
|
|
Item *m_pNext;
|
|
};
|
|
|
|
Item *m_pFirst;
|
|
Item *m_pLast;
|
|
};
|
|
|
|
|
|
class CMutex : public CWin32SyncObj
|
|
{
|
|
public:
|
|
explicit CMutex(BOOL InitialOwner = FALSE);
|
|
~CMutex(void) { };
|
|
|
|
DWORD Wait(DWORD dwTimeout = INFINITE)
|
|
{ return WaitForSingleObject(m_handle, dwTimeout); }
|
|
void Release(void)
|
|
{ ReleaseMutex(m_handle); }
|
|
|
|
private:
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CMutex(const CMutex& rhs);
|
|
CMutex& operator = (const CMutex& rhs);
|
|
};
|
|
|
|
|
|
class CEvent : public CWin32SyncObj
|
|
{
|
|
public:
|
|
explicit CEvent(BOOL bManualReset, BOOL bInitialState);
|
|
~CEvent(void) { };
|
|
|
|
BOOL Set(void)
|
|
{ return SetEvent(m_handle); }
|
|
BOOL Reset(void)
|
|
{ return ResetEvent(m_handle); }
|
|
|
|
private:
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CEvent(const CEvent& rhs);
|
|
CEvent& operator = (const CEvent& rhs);
|
|
};
|
|
|
|
|
|
class CMonitor
|
|
{
|
|
public:
|
|
CMonitor(void) { }
|
|
~CMonitor(void) { }
|
|
|
|
virtual void Lock(void)
|
|
{ m_Mutex.Wait(); }
|
|
virtual void Release(void)
|
|
{ m_Mutex.Release(); }
|
|
|
|
protected:
|
|
CMutex m_Mutex;
|
|
};
|
|
|
|
|
|
class CConditionSU; // fwd decl for use in CMonitorSU.
|
|
|
|
//
|
|
// "Signal-Urgent" monitor.
|
|
// Signalling threads are guaranteed to run immediately after the signaled
|
|
// thread exits the monitor.
|
|
//
|
|
class CMonitorSU : public CMonitor
|
|
{
|
|
public:
|
|
CMonitorSU(void)
|
|
: m_cUrgentSemCount(0) { }
|
|
~CMonitorSU(void) { }
|
|
|
|
virtual void Release(void);
|
|
|
|
protected:
|
|
int m_cUrgentSemCount;
|
|
CSemaphoreList m_UrgentSemList;
|
|
|
|
friend class CConditionSU;
|
|
};
|
|
|
|
|
|
//
|
|
// "Signal-Return" condition variable.
|
|
// Thread that is signaled is guaranteed to own the mutex lock following
|
|
// receipt of the signal.
|
|
//
|
|
class CConditionSR
|
|
{
|
|
public:
|
|
explicit CConditionSR(CMonitor& monitor)
|
|
: m_Monitor(monitor),
|
|
m_cSemCount(0) { }
|
|
|
|
virtual ~CConditionSR(void) { }
|
|
|
|
virtual void Wait(void);
|
|
virtual void Signal(void);
|
|
|
|
protected:
|
|
CMonitor& m_Monitor;
|
|
CSemaphore m_Sem;
|
|
int m_cSemCount;
|
|
};
|
|
|
|
//
|
|
// "Signal-Urgent" condition variable.
|
|
// A signaling thread is guaranteed to run first when the
|
|
// signaled thread exits the monitor.
|
|
//
|
|
class CConditionSU
|
|
{
|
|
public:
|
|
explicit CConditionSU(CMonitorSU& monitor)
|
|
: m_Monitor(monitor),
|
|
m_cSemCount(0) { }
|
|
virtual ~CConditionSU(void) { }
|
|
|
|
virtual void Wait(void);
|
|
virtual void Signal(void);
|
|
|
|
protected:
|
|
CMonitorSU& m_Monitor;
|
|
CSemaphoreList m_SemList;
|
|
int m_cSemCount;
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// An "auto lock" object based on a Win32 critical section.
|
|
// The constructor automatically calls EnterCriticalSection for the
|
|
// specified critical section. The destructor automatically calls
|
|
// LeaveCriticalSection. Note that the critical section object may
|
|
// be specified as a Win32 CRITICAL_SECTION or a CCriticalSection object.
|
|
// If using a CRITICAL_SECTION object, initialization and deletion of
|
|
// the CRITICALS_SECTION is the responsibility of the caller.
|
|
//
|
|
class AutoLockCs
|
|
{
|
|
public:
|
|
explicit AutoLockCs(CRITICAL_SECTION& cs)
|
|
: m_cLock(0),
|
|
m_pCS(&cs) { Lock(); }
|
|
|
|
void Lock(void)
|
|
{ DBGASSERT((0 <= m_cLock)); EnterCriticalSection(m_pCS); m_cLock++; }
|
|
|
|
void Release(void)
|
|
{ m_cLock--; LeaveCriticalSection(m_pCS); }
|
|
|
|
~AutoLockCs(void) { if (0 < m_cLock) Release(); }
|
|
|
|
private:
|
|
CRITICAL_SECTION *m_pCS;
|
|
int m_cLock;
|
|
};
|
|
|
|
|
|
//
|
|
// An "auto lock" object based on a Win32 Mutex object.
|
|
// The constructor automatically calls WaitForSingleObject for the
|
|
// specified mutex. The destructor automatically calls
|
|
// ReleaseMutex.
|
|
//
|
|
class AutoLockMutex
|
|
{
|
|
public:
|
|
//
|
|
// Attaches to an already-owned mutex to ensure release.
|
|
//
|
|
explicit AutoLockMutex(HANDLE hMutex)
|
|
: m_hMutex(hMutex) { }
|
|
|
|
explicit AutoLockMutex(CMutex& mutex)
|
|
: m_hMutex(mutex.Handle()) { }
|
|
|
|
AutoLockMutex(HANDLE hMutex, DWORD dwTimeout)
|
|
: m_hMutex(hMutex) { Wait(dwTimeout); }
|
|
|
|
AutoLockMutex(CMutex& mutex, DWORD dwTimeout)
|
|
: m_hMutex(mutex.Handle()) { Wait(dwTimeout); }
|
|
|
|
~AutoLockMutex(void) { ReleaseMutex(m_hMutex); }
|
|
|
|
private:
|
|
HANDLE m_hMutex;
|
|
|
|
void Wait(DWORD dwTimeout = INFINITE);
|
|
};
|
|
|
|
|
|
//
|
|
// Automatically locks a monitor on creation and releases the
|
|
// lock on destruction. Helps exception-safety of monitor functions.
|
|
//
|
|
class AutoLockMonitor
|
|
{
|
|
public:
|
|
explicit AutoLockMonitor(CMonitor& monitor)
|
|
: m_Monitor(monitor)
|
|
{ m_Monitor.Lock(); }
|
|
|
|
~AutoLockMonitor(void)
|
|
{ m_Monitor.Release(); }
|
|
|
|
private:
|
|
CMonitor& m_Monitor;
|
|
};
|
|
|
|
|
|
#endif // _INC_CSCVIEW_THDSYNC_H
|
|
|
|
|