#ifndef LOCKS_H #define LOCKS_H /////////////////////////////////////////////////////////////// // Locks.h - Define Lock classes based on: // // CriticalSection, SlimReaderWriter, Mutex // // ver 1.1 // // Language: standard C++ // // Platform: Dell Dimension T7400, Windows 7, SP #1 // // Application: Resource for DO projects // // Author: Jim Fawcett, CST 4-187, Syracuse University // // jfawcett@twcny.rr.com, (315) 443-3948 // /////////////////////////////////////////////////////////////// /* * Package Operations: * =================== * Several types of lock implementations are provided based on: * CriticalSections, Mutexes, and SlimReaderWriters * Locks based on CriticalSections and Mutexes are provided in * local and global forms. The global locks use static * CriticalSections or Mutexes so can be shared in different parts * of a package, simply by declaring an instance of the lock in * both places. * * A SRWLock class is defined, but hasn't been tested yet. * * Also, you will find a ConditionVariable class implementation, * used to build a blocking queue. See the note where the * ConditionVariable is defined, at the end of this file. */ /* * Required Files: * --------------- * Locks.h, Locks.cpp * (Thread.h, Thread.cpp are needed to run the test stub) * * Build Process: * -------------- * cl /EHa /DTEST_THREAD Locks.cpp Thread.cpp * * Maintenance History: * -------------------- * ver 1.1 : 24 Mar 2013 * - added sout, moved doLog here, uses latest threadBase * ver 1.0 : 20 Feb 2012 * - first release */ #include #include #include /////////////////////////////////////////////////////////////// // CSLock - local lock class based on Win32 CRITICAL_SECTION class CSLock { public: CSLock(); ~CSLock(); void lock(); void unlock(); operator ::CRITICAL_SECTION* (); // cast operator used with CV private: ::CRITICAL_SECTION cs; }; inline CSLock::CSLock() { ::InitializeCriticalSection(&cs); } inline CSLock::~CSLock() { ::DeleteCriticalSection(&cs); } inline void CSLock::lock() { ::EnterCriticalSection(&cs); } inline void CSLock::unlock() { ::LeaveCriticalSection(&cs); } inline CSLock::operator ::CRITICAL_SECTION* () { return &cs; } /////////////////////////////////////////////////////////////// // gCSLock - global lock class based on Win32 CRITICAL_SECTION template class gCSLock { public: gCSLock(); ~gCSLock(); void lock(); void unlock(); operator ::CRITICAL_SECTION* (); // cast operator used with CV private: static ::CRITICAL_SECTION cs; static unsigned int refCount; }; //----< statics are only initialized by first caller >--------- template ::CRITICAL_SECTION gCSLock::cs; template unsigned int gCSLock::refCount = 0; template gCSLock::gCSLock() { if(refCount==0) { if(i != -1) // doLog uses sout which uses gCSLock<-1> doLog("Initializing CriticalSection"); ::InitializeCriticalSection(&cs); } ::InterlockedIncrement(&refCount); } template gCSLock::~gCSLock() { if(::InterlockedDecrement(&refCount) == 0) { ::DeleteCriticalSection(&cs); if(i != -1) // doLog uses sout which uses gCSLock<-1> doLog("Deleting CriticalSection"); } } template void gCSLock::lock() { ::EnterCriticalSection(&cs); } template void gCSLock::unlock() { ::LeaveCriticalSection(&cs); } template inline gCSLock::operator ::CRITICAL_SECTION* () { return &cs; } /////////////////////////////////////////////////////////////// // MLock - local lock class based on Win32 Mutex class MLock { public: MLock(); ~MLock(); void lock(); void unlock(); private: ::HANDLE hMutex; }; inline MLock::MLock() { hMutex = CreateMutexA ( NULL, // security attributes false, // won't start locked NULL // no name, so create anonymous mutex ); if(hMutex == NULL) throw std::exception("mutex creation failed"); } inline MLock::~MLock() { CloseHandle(hMutex); } inline void MLock::lock() { ::WaitForSingleObject(hMutex, INFINITE); } inline void MLock::unlock() { ReleaseMutex(hMutex); } /////////////////////////////////////////////////////////////// // gMLock - global lock class based on Win32 Mutex template class gMLock { public: gMLock(); ~gMLock(); void lock(); void unlock(); private: static ::HANDLE hMutex; static unsigned int refCount; }; //----< statics are only initialized by first caller >--------- template ::HANDLE gMLock::hMutex; template unsigned int gMLock::refCount = 0; template gMLock::gMLock() { if(refCount == 0) { hMutex = CreateMutexA ( NULL, // security attributes false, // won't start locked NULL // no name, so create anonymous mutex ); if(hMutex == NULL) throw std::exception("mutex creation failed"); doLog("Creating global mutex"); } ::InterlockedIncrement(&refCount); } template gMLock::~gMLock() { if(::InterlockedDecrement(&refCount) == 0) { ::CloseHandle(hMutex); doLog("closing global mutex handle"); } } template void gMLock::lock() { ::WaitForSingleObject(hMutex, INFINITE); } template void gMLock::unlock() { ::ReleaseMutex(hMutex); } /////////////////////////////////////////////////////////////// // SRWLock - local lock class based on Win32 SRWLock class SRWLock { public: SRWLock(); ~SRWLock(); void lockExclusive(); void lockShared(); void unlockExclusive(); void unlockShared(); private: ::SRWLOCK srw; }; inline SRWLock::SRWLock() { ::InitializeSRWLock(&srw); } inline SRWLock::~SRWLock() { // no Destroy or Delete function // OS manages this - not clear how } inline void SRWLock::lockExclusive() { ::AcquireSRWLockExclusive(&srw); } inline void SRWLock::lockShared() { ::AcquireSRWLockShared(&srw); } inline void SRWLock::unlockExclusive() { ::ReleaseSRWLockExclusive(&srw); } inline void SRWLock::unlockShared() { ::ReleaseSRWLockShared(&srw); } /////////////////////////////////////////////////////////////// // gSRWLock - global lock class based on Win32 SRWLock template class gSRWLock { public: gSRWLock(); ~gSRWLock(); void lockExclusive(); void lockShared(); void unlockExclusive(); void unlockShared(); private: static ::SRWLOCK srw; static unsigned int refCount; }; //----< statics are only initialized by first caller >--------- template ::SRWLOCK gSRWLock::srw; template unsigned int gSRWLock::refCount = 0; template gSRWLock::gSRWLock() { if(refCount==0) { doLog("Initializing SRWLock"); ::InitializeSRWLock(&srw); } ::InterlockedIncrement(&refCount); } template gSRWLock::~gSRWLock() { if(::InterlockedDecrement(&refCount) == 0) { // do nothing doLog("SRWLock destructor called"); } } template void gSRWLock::lockExclusive() { ::AquireSRWLockExclusive(&srw); } template void gSRWLock::lockShared() { ::AquireSRWLockShared(&srw); } template void gSRWLock::unlockExclusive() { ::ReleaseSRWLockExclusive(&srw); } template void gSRWLock::unlockShared() { ::ReleaseSRWLockShared(&srw); } /////////////////////////////////////////////////////////////////////////// // CSConditionVariable - local ConditionVariable based on CriticalSection /* * ConditionVariables work in concert with a compatible lock to allow * a consumer to wait on an empty resource until a producer supplies * an instance for consumption. * * The ConditionVariable (CV) and lock must share an underlying synchronizing * construct, like a CriticalSection (CS). The consumer locks the resource, then * passes its lock to the CV's sleep function, thus waiting inside the lock. * The CV blocks the consumer but unlocks the lock so producers can get at the * resource. When a producer has supplied a resource item it calls the CV's wake() * function to allow a waiting thread to consume. * * This ConditionVariable is based on a CriticalSection, so you use a CriticalSection * based lock to pass to the sleep function. */ class CSConditionVariable { public: CSConditionVariable(); ~CSConditionVariable(); void sleep(CSLock& csl); void wake(); void wakeAll(); private: ::CONDITION_VARIABLE cv; }; inline CSConditionVariable::CSConditionVariable() { ::InitializeConditionVariable(&cv); } inline CSConditionVariable::~CSConditionVariable() { // nothing to do for ConditionVariable } inline void CSConditionVariable::sleep(CSLock& lock) { ::SleepConditionVariableCS(&cv, (::CRITICAL_SECTION*)lock, INFINITE); } inline void CSConditionVariable::wake() { ::WakeConditionVariable(&cv); } inline void CSConditionVariable::wakeAll() { ::WakeAllConditionVariable(&cv); } /////////////////////////////////////////////////////////////////////////// // SRWConditionVariable - local ConditionVariable based on SRWLock // todo: define SRWConditionVariable ///////////////////////////////////////////////////////////////////// // syncOut class class syncOut { public: syncOut(std::ostream& out); template syncOut& operator<<(const T& t); syncOut& operator<<(syncOut& (*op)(syncOut&)); template void operator()(const T& t); void flush(); private: gCSLock<-1> _l; std::ostream& _out; }; //----< constructor >------------------------------------------------ inline syncOut::syncOut(std::ostream& out) : _out(out) {} //----< insertion >-------------------------------------------------- template syncOut& syncOut::operator<<(const T& t) { _l.lock(); _out << t; _out.flush(); _l.unlock(); return *this; } //----< insertion >-------------------------------------------------- inline syncOut& syncOut::operator<<(syncOut& (*op)(syncOut&)) { return (*op)(*this); } //----< functor >---------------------------------------------------- template void syncOut::operator()(const T& t) { _l.lock(); _out << t; _out.flush(); _l.unlock(); } //----< flush output stream >---------------------------------------- inline void syncOut::flush() { _out.flush(); } //----< lock manipulator >------------------------------------------- inline syncOut& locker(syncOut& so) { gCSLock<-1>().lock(); return so; } //----< unlock manipulator >----------------------------------------- inline syncOut& unlocker(syncOut& so) { gCSLock<-1>().unlock(); return so; } extern syncOut sout; ///////////////////////////////////////////////////////////////////// // debug Macro inline void doLog(const char* pChar) { #ifdef DOLOG sout << locker << "\n " << pChar << unlocker; #endif } #endif