Subj : Re: stl & threads To : comp.programming.threads From : Uenal Mutlu Date : Wed May 25 2005 03:43 am "Uenal Mutlu" <520001085531-0001@t-online.de> wrote > > You should make each object you want to share (ie. use) among multiple > threads 'lockable'. I recommend to add a mutex to each such object > by using constructs like those below: > > class mutex > { > public: > mutex(bool AfRecursiveMutex = true); > ~mutex(); > void Lock(); > void Unlock(); > bool IsLockedByAny() const; > bool IsLockedByMe() const; > // ... > }; Here's a standard implementation of mutex using CriticalSection (Windows): class mutex { // mutex using CriticalSection of Win32 public: mutex(bool AfRecursiveMutex = true) : fRecursiveMutex(AfRecursiveMutex) { cLocked = 0; dwThrId = 0; InitializeCriticalSection(&cs); } ~mutex() { DeleteCriticalSection(&cs); } bool IsLockedByAny() const { return cLocked > 0; } bool IsLockedByMe() const { return cLocked > 0 && dwThrId == GetCurrentThreadId(); } size_t GetLockCount() const { return cLocked; } private: mutex(const mutex& Ax); // copy ctor: prohibit copying mutex& operator=(mutex&); // prohibit assignment friend class Locker; // force Lock() and Unlock() be called only via Locker object void Lock() { EnterCriticalSection(&cs); assert(fRecursiveMutex ? true : !cLocked); ++cLocked; dwThrId = GetCurrentThreadId(); } void Unlock() { assert(cLocked > 0 && dwThrId == GetCurrentThreadId()); if (!(--cLocked)) dwThrId = 0; LeaveCriticalSection(&cs); } private: CRITICAL_SECTION cs; size_t cLocked; DWORD dwThrId; const bool fRecursiveMutex; }; > And by using the following you can extend any object with a default > contructor to a 'Lockable' object, for example all STL containers: > > template class Lockable : public T > { > public: > mutex mx; // a mutex for the object > Lockable() {} > private: > Lockable(const Lockable&); // copy ctor: prohibit copying > }; Add this to the private section: Lockable& operator=(Lockable&); // prohibit assignment > Then, in applic code one would use something like the following > automatic helper object to do the actual locking/unlocking: > > class Locker > { > public: > Locker(mutex& Amx) : mx(Amx) { mx.Lock(); } > ~Locker() { mx.Unlock(); } > private: > mutex& mx; > }; Add these to the private section: Locker(const Locker&); // copy ctor: prohibit copying Locker& operator=(Locker&); // prohibit assignment > Example usage: > > Lockable > vec; > > void* thrprocA(void* Ap) > { > Locker L(vec.mx); > // it is safe to modify vec > } > > void* thrprocB(void* Ap) > { > Locker L(vec.mx); > // it is safe to modify vec > } .