/** \file G3D/GMutex.h \created 2005-09-22 \edited 2013-04-03 */ #ifndef G3D_GMutex_h #define G3D_GMutex_h #include "G3D/platform.h" #include "G3D/AtomicInt32.h" #include "G3D/debugAssert.h" #include #ifndef G3D_WINDOWS # include # include #endif #if defined(G3D_LINUX) || defined(G3D_OSX) # include // For usleep #endif namespace G3D { /** \brief A mutual exclusion lock that busy-waits when locking. On a machine with one (significant) thread per processor core, a Spinlock may be substantially faster than a mutex. \sa G3D::GThread, G3D::GMutex, G3D::AtomicInt32 */ class Spinlock { private: AtomicInt32 x; public: inline Spinlock() : x(0) {} /** Busy waits until the lock is unlocked, then locks it exclusively. Returns true if the lock succeeded on the first try (indicating no contention). Unlike a G3D::GMutex, a single thread cannot re-enter Spinlock::lock() that it already locked. */ inline bool lock() { bool first = true; while (x.compareAndSet(0, 1) == 1) { first = false; # ifdef G3D_WINDOWS Sleep(0); # else usleep(0); # endif } return first; } inline void unlock() { x.compareAndSet(1, 0); } }; /** \brief Mutual exclusion lock used for synchronization. @sa G3D::GThread, G3D::AtomicInt32, G3D::Spinlock */ class GMutex { private: # ifdef G3D_WINDOWS CRITICAL_SECTION m_handle; # else pthread_mutex_t m_handle; pthread_mutexattr_t m_attr; # endif // Not implemented on purpose, don't use GMutex(const GMutex &mlock); GMutex &operator=(const GMutex &); bool operator==(const GMutex&); public: GMutex(); ~GMutex(); /** Locks the mutex or blocks until available. */ void lock(); /** Locks the mutex if it not already locked. Returns true if lock successful, false otherwise. */ bool tryLock(); /** Unlocks the mutex. */ void unlock(); }; /** Automatically locks while in scope. */ class GMutexLock { private: GMutex* m; // Not implemented on purpose, don't use GMutexLock(const GMutexLock &mlock); GMutexLock &operator=(const GMutexLock &); bool operator==(const GMutexLock&); public: GMutexLock(GMutex* mutex) { m = mutex; m->lock(); } ~GMutexLock() { m->unlock(); } }; } // G3D #endif