#ifndef LOCKINGPTR_H #define LOCKINGPTR_H ///////////////////////////////////////////////////////////////////// // lockingPtr.h - provides serialized access to class objects // // ver 1.1 // // Language: Visual C++, ver 6.0 // // Platform: Dell Dimension 8100, Win2000, SP 2 // // Application: CSE691 - Useful for projects #2 and #3 // // Author: Jim Fawcett, CST 2-187, Syracuse University // // (315) 443-3948, jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////////// /* This class follows closely that described by Andrei Alexandrescu in "Generic:volatile -- Multithreaded Programmer's Best Friend ... ", C/C++ Users Journal, Feb 2001. Class Operation =============== An object of the lockingPtr class provides serialized access to objects it references. It implements a smart pointer that uses an object of the Mutex class to provide a lock mechanism. Public Interface for lockingPtr: ================================ myObjType myObj; // some arbitrary object Mutex mtx; // provides a lock lockingPtr pMyObj(myObj,mtx); // serializes access pMyObj->memberFunction(args); // to myObj lockingPtr(*pMyObj,mtx)->memberFunction(args); // create and use temporary // lockingPtr This last statement is a very useful idiom. It causes the lockingPtr object to be constructed, used, and immediately destroyed. Thus, it provides a single locked access to an object with only one line of code. Public Interface for Mutex: =========================== mtx.lock(); // acquire a lock cout << "\n a serialized use of cout" << endl; mtx.unlock(); // release the lock */ // /////////////////////////////////////////////////////////////// // build process // /////////////////////////////////////////////////////////////// // required files: // // lockingPtr.h, lockingPtr.cpp // // // // command line compile: // // cl /GX /GZ /DTEST_LOCKINGPTR lockingPtr.cpp // /////////////////////////////////////////////////////////////// /* Maintenance History: ==================== ver 1.0 : 10 Oct 2001 - first release ver 1.1 : 23 Oct 2001 - added missing #include - added test stub and more detail to manual page - added annunciators used during lockingPtr test, e.g., when TEST_LOCKINGPTR is defined - removed unnecessary #include */ // /////////////////////////////////////////////////////////////// // class declaration for Mutex // /////////////////////////////////////////////////////////////// #include class Mutex { public: Mutex(); ~Mutex(); void lock(); void unlock(); private: CRITICAL_SECTION cs; }; //----< default constructor >---------------------------------- inline Mutex::Mutex() { InitializeCriticalSection(&cs); } //----< destructor >------------------------------------------- inline Mutex::~Mutex() { DeleteCriticalSection(&cs); } //----< set lock >--------------------------------------------- inline void Mutex::lock() { EnterCriticalSection(&cs); } //----< remove lock >------------------------------------------ inline void Mutex::unlock() { LeaveCriticalSection(&cs); } // /////////////////////////////////////////////////////////////// // class declaration for lockingPtr // /////////////////////////////////////////////////////////////// template class lockingPtr { public: lockingPtr(volatile T &obj, Mutex &mtx); ~lockingPtr(); T& operator*(); T* operator->(); private: T* _pObj; Mutex *_pMtx; lockingPtr(const lockingPtr&); lockingPtr& operator=(const lockingPtr&); }; //----< constructor takes object to lock and Mutex >----------- template inline lockingPtr::lockingPtr(volatile T &obj, Mutex &mtx) : _pObj(const_cast(&obj)), _pMtx(&mtx) { #ifdef TEST_LOCKINGPTR cout << "\n constructing a LockingPtr object - calls lock()"; cout.flush(); #endif mtx.lock(); } //----< destructor >------------------------------------------- template inline lockingPtr::~lockingPtr() { _pMtx->unlock(); #ifdef TEST_LOCKINGPTR cout << "\n destroying a LockingPtr object - calls unlock()"; cout.flush(); #endif } // //----< get locked object >------------------------------------ template inline T& lockingPtr::operator*() { #ifdef TEST_LOCKINGPTR cout << "\n accessing contents of locked object"; cout.flush(); #endif return *_pObj; } //----< access locked object's members >----------------------- template inline T* lockingPtr::operator->() { #ifdef TEST_LOCKINGPTR cout << "\n accessing member of locked object"; cout.flush(); #endif return _pObj; } #endif