|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: CiSem.Hxx
//
// Contents: Semaphore classes
//
// Classes: CMutexSem - Mutex semaphore class
// CStaticMutexSem - statically allocated Mutex semaphore class
// CEventSem - Event semaphore
//
// History: 21-Jun-91 AlexT Created.
//
//----------------------------------------------------------------------------
#pragma once
//+---------------------------------------------------------------------------
//
// Class: CMutexSem (mxs)
//
// Purpose: Mutex Semaphore services
//
// Interface: Request - acquire semaphore
// Release - release semaphore
//
// History: 14-Jun-91 AlexT Created.
// 30-oct-91 SethuR 32 bit implementation
//
// Notes: This class wraps a mutex semaphore. Mutex semaphores protect
// access to resources by only allowing one client through at a
// time. The client Requests the semaphore before accessing the
// resource and Releases the semaphore when it is done. The
// same client can Request the semaphore multiple times (a nest
// count is maintained).
//
//----------------------------------------------------------------------------
class CMutexSem { public: CMutexSem() { InitializeCriticalSection( &_cs ); _fInitedCS = TRUE; }
CMutexSem(BOOL fInit) { if (fInit) { InitializeCriticalSection( &_cs ); _fInitedCS = TRUE; } else { memset( &_cs, 0, sizeof _cs ); _fInitedCS = FALSE; } }
~CMutexSem() { if (_fInitedCS) { DeleteCriticalSection( &_cs ); _fInitedCS = FALSE; } }
void Init() { InitializeCriticalSection(&_cs); _fInitedCS = TRUE; }
void Request() { #if DBG == 1
if (!_fInitedCS) DbgPrint( "CMutexSem not initialized!\n" ); #endif
EnterCriticalSection( &_cs ); }
void Release() { LeaveCriticalSection( &_cs ); }
BOOL Try() { return TryEnterCriticalSection( &_cs ); }
BOOL IsHeld() { return ( LongToHandle( GetCurrentThreadId() ) == _cs.OwningThread ); }
protected: BOOL _fInitedCS; CRITICAL_SECTION _cs; };
//+---------------------------------------------------------------------------
//
// Class: CStaticMutexSem
//
// Purpose: Mutex Semaphore services
//
// Interface: Init - initializer (two-step)
// Request - acquire semaphore
// Release - release semaphore
//
// History: 20 May 99 AlawW Created.
//
// Notes: Like a CMutexSem, but initialization is deferred. Useful
// for statically allocated critical sections where there is
// the (unlikely) potential to get a STATUS_NO_MEMORY exception
// thrown from the InitializeCriticalSection call.
//
//----------------------------------------------------------------------------
class CStaticMutexSem : public CMutexSem { public: CStaticMutexSem( ) : CMutexSem( FALSE ) {} };
//+---------------------------------------------------------------------------
//
// Class: CLock (lck)
//
// Purpose: Lock using a Mutex Semaphore
//
// History: 02-Oct-91 BartoszM Created.
//
// Notes: Simple lock object to be created on the stack.
// The constructor acquires the semaphor, the destructor
// (called when lock is going out of scope) releases it.
//
//----------------------------------------------------------------------------
class CLock { public: CLock( CMutexSem& mxs ) : _mxs ( mxs ) { _mxs.Request(); }
~CLock() { _mxs.Release(); }
private: CMutexSem & _mxs; };
#define CPriLock CLock
//+---------------------------------------------------------------------------
//
// Class: CReleasableLock
//
// Purpose: Lock using a Mutex Semaphore that can be released/requested
//
// History: 16-Sep-96 dlee Created.
//
//----------------------------------------------------------------------------
class CReleasableLock { public:
CReleasableLock( CMutexSem& mxs, BOOL fHeld = TRUE ) : _fHeld( fHeld ), _mxs(mxs) { if ( fHeld ) _mxs.Request(); }
~CReleasableLock() { if ( _fHeld ) _mxs.Release(); }
void Release() { Win4Assert( _fHeld ); _mxs.Release(); _fHeld = FALSE; }
void Request() { Win4Assert( !_fHeld ); _mxs.Request(); _fHeld = TRUE; }
BOOL Try() { Win4Assert( !_fHeld ); return ( _fHeld = _mxs.Try() ); }
BOOL IsHeld() const { return _fHeld; }
private: CMutexSem & _mxs; BOOL _fHeld; };
//+---------------------------------------------------------------------------
//
// Class: CEventSem (evs)
//
// Purpose: Event Semaphore services
//
// Interface: Wait - wait for semaphore to be signalled
// Set - set signalled state
// Reset - clear signalled state
// Pulse - set and clear semaphore
//
// History: 21-Jun-91 AlexT Created.
// 27-Feb-92 BartoszM Use exceptions for errors
//
// Notes: Used for communication between consumers and producers.
// Consumer threads block by calling Wait. A producer
// calls Set waking up all the consumers who go ahead
// and consume until there's nothing left. They call
// Reset, release whatever lock protected the resources,
// and call Wait. There has to be a separate lock
// to protect the shared resources.
// Remember: call Reset under lock.
// don't call Wait under lock.
//
//----------------------------------------------------------------------------
class CEventSem { public: inline CEventSem( BOOL fInitState=FALSE, const LPSECURITY_ATTRIBUTES lpsa=NULL ); inline CEventSem( HANDLE hEvent ); inline CEventSem( DWORD dwMustBeZero, WCHAR const * pwszName, DWORD dwAccess = EVENT_ALL_ACCESS | EVENT_MODIFY_STATE | SYNCHRONIZE ); inline CEventSem( WCHAR const * pwszName, BOOL fInitState = FALSE, const LPSECURITY_ATTRIBUTES lpsa = NULL );
HANDLE AcquireHandle() { HANDLE hVal = _hEvent; _hEvent = 0; return hVal; }
void Create() { Win4Assert( 0 == _hEvent );
_hEvent = CreateEventW( 0, TRUE, FALSE, 0 ); if ( 0 == _hEvent ) THROW( CException() ); }
inline ~CEventSem();
inline ULONG Wait(DWORD dwMilliseconds = INFINITE, BOOL fAlertable = FALSE ); inline void Set(); inline void Reset(); inline void Pulse(); inline const HANDLE GetHandle() const { return _hEvent; }
private: HANDLE _hEvent; };
//+---------------------------------------------------------------------------
//
// Class: CAutoEventSem
//
// Purpose: Auto-reset version of CEventSem
//
// History: 16-Sep-96 dlee Created.
//
//----------------------------------------------------------------------------
class CAutoEventSem { public: CAutoEventSem() { _hEvent = CreateEventW( 0, FALSE, FALSE, 0 ); if ( 0 == _hEvent ) THROW( CException() ); }
~CAutoEventSem() { if ( 0 != _hEvent ) { BOOL f = CloseHandle ( _hEvent ); Win4Assert( f && "can't close event handle" ); } }
void Set() { if ( !SetEvent ( _hEvent ) ) THROW( CException() ); }
void Wait() { WaitForSingleObject( _hEvent, INFINITE ); }
const HANDLE GetHandle() const { return _hEvent; }
private: HANDLE _hEvent; };
//+---------------------------------------------------------------------------
//
// Class: CEventSetter
//
// Purpose: Sets an event when exiting scope
//
// History: 16-Sep-96 dlee Created.
//
//----------------------------------------------------------------------------
class CEventSetter { public: CEventSetter( CAutoEventSem &event ) : _event( event ) { }
~CEventSetter() { _event.Set(); }
private: CAutoEventSem & _event; };
//+---------------------------------------------------------------------------
//
// Member: CEventSem::CEventSem
//
// Synopsis: Creates an event
//
// Arguments: [bInitState] -- TRUE: signaled state, FALSE non-signaled
// [lpsa] -- security attributes
//
// History: 27-Feb-92 BartoszM Created
//
//----------------------------------------------------------------------------
inline CEventSem::CEventSem ( BOOL bInitState, const LPSECURITY_ATTRIBUTES lpsa ) { _hEvent = CreateEventW( lpsa, TRUE, bInitState, 0 ); if ( _hEvent == 0 ) { THROW( CException() ); } }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::CEventSem
//
// Synopsis: Opens an event
//
// Arguments: [hEvent] -- handle of event to open
// [bInitState] -- TRUE: signaled state, FALSE non-signaled
//
// History: 02-Jul-94 DwightKr Created
//
//----------------------------------------------------------------------------
inline CEventSem::CEventSem ( HANDLE hEvent ) : _hEvent( hEvent ) { }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::CEventSem
//
// Synopsis: Constructor to "open" an already existing event sem.
//
// Arguments: [dwMustBeZero] - Just to distinguish from the constructor
// used to "create" named event semaphores.
// [pwszName] - Name of the semaphore
// [dwAccess] - Access.
//
// History: 2-15-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline CEventSem::CEventSem( DWORD dwMustBeZero, WCHAR const * pwszName, DWORD dwAccess ) { Win4Assert( 0 == dwMustBeZero && 0 != pwszName );
_hEvent = OpenEventW( dwAccess, TRUE, pwszName ); if ( 0 == _hEvent ) { THROW( CException() ); } }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::CEventSem
//
// Synopsis: Constructor to "create" a named event semaphore.
//
// Arguments: [pwszName] - Name of the event semaphore.
// [fInitState] -
// [lpsa] -
//
// History: 2-15-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline CEventSem::CEventSem( WCHAR const * pwszName, BOOL fInitState, const LPSECURITY_ATTRIBUTES lpsa ) {
_hEvent = CreateEventW( lpsa, TRUE, fInitState, pwszName ); if ( _hEvent == 0 ) { THROW( CException() ); } }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::~CEventSem
//
// Synopsis: Releases event
//
// History: 27-Feb-92 BartoszM Created
//
//----------------------------------------------------------------------------
inline CEventSem::~CEventSem () { if ( 0 != _hEvent ) { BOOL f = CloseHandle( _hEvent ); Win4Assert( f && "can't close event handle" ); } }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::Set
//
// Synopsis: Set the state to signaled. Wake up waiting threads.
// For manual events the state remains set
// until Reset is called
//
// History: 27-Feb-92 BartoszM Created
//
//----------------------------------------------------------------------------
inline void CEventSem::Set() { if ( !SetEvent ( _hEvent ) ) { THROW( CException() ); } }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::Reset
//
// Synopsis: Reset the state to non-signaled. Threads will block.
//
// History: 27-Feb-92 BartoszM Created
//
//----------------------------------------------------------------------------
inline void CEventSem::Reset() { if ( !ResetEvent ( _hEvent ) ) { THROW( CException() ); } }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::Wait
//
// Synopsis: Block until event set
//
// History: 27-Feb-92 BartoszM Created
//
//----------------------------------------------------------------------------
inline ULONG CEventSem::Wait( DWORD msec, BOOL fAlertable ) { DWORD res = WaitForSingleObjectEx ( _hEvent, msec, fAlertable );
if ( 0xffffffff == res ) { THROW( CException() ); } return res; }
//+---------------------------------------------------------------------------
//
// Member: CEventSem::Pulse
//
// Synopsis: Set the state to signaled. Wake up waiting threads.
//
// History: 27-Feb-92 BartoszM Created
//
//----------------------------------------------------------------------------
inline void CEventSem::Pulse() { if ( !PulseEvent ( _hEvent ) ) { THROW( CException() ); } }
|