132 lines
2.5 KiB
C
132 lines
2.5 KiB
C
|
/**
|
||
|
\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 <string>
|
||
|
|
||
|
#ifndef G3D_WINDOWS
|
||
|
# include <pthread.h>
|
||
|
# include <signal.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(G3D_LINUX) || defined(G3D_OSX)
|
||
|
# include <unistd.h> // 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
|