You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

264 lines
5.3 KiB

////////////////////////////////////////////////////////////////////
// CriticalSection.h
//
// Copyright 2007 cDc@seacave
// Distributed under the Boost Software License, Version 1.0
// (See http://www.boost.org/LICENSE_1_0.txt)
#ifndef __SEACAVE_CRITCALSECTION_H__
#define __SEACAVE_CRITCALSECTION_H__
// I N C L U D E S /////////////////////////////////////////////////
#include "Thread.h"
// D E F I N E S ///////////////////////////////////////////////////
namespace SEACAVE {
// S T R U C T S ///////////////////////////////////////////////////
class CriticalSection
{
#ifdef _MSC_VER
public:
CriticalSection() {
InitializeCriticalSection(&cs);
}
~CriticalSection() {
DeleteCriticalSection(&cs);
}
void Clear() {
DeleteCriticalSection(&cs);
InitializeCriticalSection(&cs);
}
void Enter() {
EnterCriticalSection(&cs);
}
bool TryEnter() {
return (TryEnterCriticalSection(&cs) != 0);
}
void Leave() {
LeaveCriticalSection(&cs);
}
protected:
CRITICAL_SECTION cs;
#else
public:
CriticalSection() {
#ifdef __APPLE__
pthread_mutex_init(&mtx, NULL);
#else
mtx = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
#endif
}
~CriticalSection() { pthread_mutex_destroy(&mtx); }
void Clear() {
pthread_mutex_destroy(&mtx);
#ifdef __APPLE__
pthread_mutex_init(&mtx, NULL);
#else
mtx = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
#endif
}
void Enter() { pthread_mutex_lock(&mtx); }
bool TryEnter() { return (pthread_mutex_trylock(&mtx) == 0); }
void Leave() { pthread_mutex_unlock(&mtx); }
pthread_mutex_t& getMutex() { return mtx; }
protected:
pthread_mutex_t mtx;
#endif
private:
CriticalSection(const CriticalSection&);
CriticalSection& operator=(const CriticalSection&);
};
/**
* A fast, non-recursive and unfair implementation of the Critical Section.
* It is meant to be used in situations where the risk for lock conflict is very low,
* i e locks that are held for a very short time. The lock is _not_ recursive, i e if
* the same thread will try to grab the lock it'll hang in a never-ending loop. The lock
* is not fair, i e the first to try to enter a locked lock is not guaranteed to be the
* first to get it when it's freed...
*/
class FastCriticalSection {
public:
FastCriticalSection() : state(0) {}
void Clear() {
Thread::safeExchange(state, 0);
}
void Enter() {
while (Thread::safeCompareExchange(state, 0, 1) != 0)
Thread::yield();
}
bool TryEnter() {
return (Thread::safeCompareExchange(state, 0, 1) == 0);
}
void Leave() {
Thread::safeDec(state);
}
protected:
volatile Thread::safe_t state;
};
template<class T>
class SimpleLock {
public:
SimpleLock(T& aCs) : cs(aCs) { cs.Enter(); }
~SimpleLock() { cs.Leave(); }
protected:
T& cs;
};
template<class T>
class SimpleLockTry {
public:
SimpleLockTry(T& aCs) : cs(aCs) { bLocked = cs.TryEnter(); }
~SimpleLockTry() { if (bLocked) cs.Leave(); }
bool IsLocked() const { return bLocked; }
protected:
T& cs;
bool bLocked;
};
typedef SimpleLock<CriticalSection> Lock;
typedef SimpleLock<FastCriticalSection> FastLock;
typedef SimpleLockTry<CriticalSection> LockTry;
typedef SimpleLockTry<FastCriticalSection> FastLockTry;
class RWLock
{
public:
RWLock() : cs(), readers(0) {}
~RWLock() { ASSERT(readers==0); }
void Clear() { cs.Clear(); readers = 0; }
// Read
void EnterRead() {
Lock l(cs);
++readers;
}
bool TryEnterRead() {
LockTry l(cs);
if (!l.IsLocked())
return false;
++readers;
return true;
}
void LeaveRead() {
Lock l(cs);
ASSERT(readers > 0);
--readers;
}
bool TryLeaveRead() {
LockTry l(cs);
if (!l.IsLocked())
return false;
ASSERT(readers > 0);
--readers;
return true;
}
// Write
void EnterWrite() {
cs.Enter();
while (readers) {
cs.Leave();
Thread::yield();
cs.Enter();
}
}
bool TryEnterWrite() {
if (cs.TryEnter()) {
if (readers == 0)
return true;
cs.Leave();
}
return false;
}
void LeaveWrite() {
cs.Leave();
}
private:
RWLock(const RWLock&);
RWLock& operator=(const RWLock&);
protected:
CriticalSection cs;
unsigned readers;
};
class RLock {
public:
RLock(RWLock& aCs) : cs(aCs) { cs.EnterRead(); }
~RLock() { cs.LeaveRead(); }
private:
RLock(const RLock&);
RLock& operator=(const RLock&);
protected:
RWLock& cs;
};
class RLockTry {
public:
RLockTry(RWLock& aCs) : cs(aCs) { bLocked = cs.TryEnterRead(); }
~RLockTry() { if (bLocked) cs.LeaveRead(); }
bool IsLocked() const { return bLocked; }
bool TryEnter() { return (bLocked = cs.TryEnterRead()); }
bool TryLeave() { return !(bLocked = !cs.TryLeaveRead()); }
private:
RLockTry(const RLockTry&);
RLockTry& operator=(const RLockTry&);
protected:
RWLock& cs;
bool bLocked;
};
class WLock {
public:
WLock(RWLock& aCs) : cs(aCs) { cs.EnterWrite(); }
~WLock() { cs.LeaveWrite(); }
private:
WLock(const WLock&);
WLock& operator=(const WLock&);
protected:
RWLock& cs;
};
class WLockTry {
public:
WLockTry(RWLock& aCs) : cs(aCs) { bLocked = cs.TryEnterWrite(); }
~WLockTry() { if (bLocked) cs.LeaveWrite(); }
bool IsLocked() const { return bLocked; }
bool TryEnter() { return (bLocked = cs.TryEnterWrite()); }
private:
WLockTry(const WLockTry&);
WLockTry& operator=(const WLockTry&);
protected:
RWLock& cs;
bool bLocked;
};
/*----------------------------------------------------------------*/
} // namespace SEACAVE
#endif // __SEACAVE_CRITCALSECTION_H__