diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
commit | 9a2a524f1e311853d08050be2dcdddc09ac7759a (patch) | |
tree | d8e4a24169fce88c2d89931d58514889a0bcb0ea /shared/loki/Threads.h | |
parent | 2.3 (diff) | |
download | FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.gz FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.bz2 FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.zip |
3.0
Diffstat (limited to 'shared/loki/Threads.h')
-rw-r--r-- | shared/loki/Threads.h | 609 |
1 files changed, 609 insertions, 0 deletions
diff --git a/shared/loki/Threads.h b/shared/loki/Threads.h new file mode 100644 index 00000000..cb44f094 --- /dev/null +++ b/shared/loki/Threads.h @@ -0,0 +1,609 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_THREADS_INC_ +#define LOKI_THREADS_INC_ + +// $Id: Threads.h 902 2008-11-10 05:47:06Z rich_sposato $ + + +/// @defgroup ThreadingGroup Threading +/// Policies to for the threading model: +/// +/// - SingleThreaded +/// - ObjectLevelLockable +/// - ClassLevelLockable +/// +/// All classes in Loki have configurable threading model. +/// +/// The macro LOKI_DEFAULT_THREADING selects the default +/// threading model for certain components of Loki +/// (it affects only default template arguments) +/// +/// \par Usage: +/// +/// To use a specific threading model define +/// +/// - nothing, single-theading is default +/// - LOKI_OBJECT_LEVEL_THREADING for object-level-threading +/// - LOKI_CLASS_LEVEL_THREADING for class-level-threading +/// +/// \par Supported platfroms: +/// +/// - Windows (windows.h) +/// - POSIX (pthread.h): +/// No recursive mutex support with pthread. +/// This means: calling Lock() on a Loki::Mutex twice from the +/// same thread before unlocking the mutex deadlocks the system. +/// To avoid this redesign your synchronization. See also: +/// http://sourceforge.net/tracker/index.php?func=detail&aid=1516182&group_id=29557&atid=396647 + + +#include <cassert> + +#if defined(LOKI_CLASS_LEVEL_THREADING) || defined(LOKI_OBJECT_LEVEL_THREADING) + + #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::ClassLevelLockable + + #if defined(LOKI_CLASS_LEVEL_THREADING) && !defined(LOKI_OBJECT_LEVEL_THREADING) + #define LOKI_DEFAULT_THREADING ::Loki::ClassLevelLockable + #else + #define LOKI_DEFAULT_THREADING ::Loki::ObjectLevelLockable + #endif + + #if defined(_WIN32) || defined(_WIN64) + #include <windows.h> + #define LOKI_WINDOWS_H + #else + #include <pthread.h> + #define LOKI_PTHREAD_H + #endif + +#else + + #define LOKI_DEFAULT_THREADING ::Loki::SingleThreaded + #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::SingleThreaded + +#endif + +#ifndef LOKI_DEFAULT_MUTEX +#define LOKI_DEFAULT_MUTEX ::Loki::Mutex +#endif + +#ifdef LOKI_WINDOWS_H + +#define LOKI_THREADS_MUTEX(x) CRITICAL_SECTION (x); +#define LOKI_THREADS_MUTEX_INIT(x) ::InitializeCriticalSection (x) +#define LOKI_THREADS_MUTEX_DELETE(x) ::DeleteCriticalSection (x) +#define LOKI_THREADS_MUTEX_LOCK(x) ::EnterCriticalSection (x) +#define LOKI_THREADS_MUTEX_UNLOCK(x) ::LeaveCriticalSection (x) +#define LOKI_THREADS_LONG LONG +#define LOKI_THREADS_MUTEX_CTOR(x) + +#define LOKI_THREADS_ATOMIC_FUNCTIONS \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval *= val; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval /= val; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicIncrement(volatile IntType& lval) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + ++lval; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + --lval; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static void AtomicAssign(volatile IntType& lval, const IntType val) \ + { InterlockedExchange(&const_cast<IntType&>(lval), val); } \ + \ + static void AtomicAssign(IntType& lval, volatile const IntType& val) \ + { InterlockedExchange(&lval, val); } \ + \ + static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + ++lval; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + --lval; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicAdd(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval += val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicSubtract(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval -= val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval *= val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval /= val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } + +#elif defined(LOKI_PTHREAD_H) + + +#define LOKI_THREADS_MUTEX(x) pthread_mutex_t (x); + +#define LOKI_THREADS_MUTEX_INIT(x) ::pthread_mutex_init(x, 0) + +// define to 1 to enable recursive mutex support +#if 0 +// experimental recursive mutex support +#define LOKI_THREADS_MUTEX_CTOR(x) : x(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#else +// no recursive mutex support +#define LOKI_THREADS_MUTEX_CTOR(x) +#endif + +#define LOKI_THREADS_MUTEX_DELETE(x) ::pthread_mutex_destroy (x) +#define LOKI_THREADS_MUTEX_LOCK(x) ::pthread_mutex_lock (x) +#define LOKI_THREADS_MUTEX_UNLOCK(x) ::pthread_mutex_unlock (x) +#define LOKI_THREADS_LONG long + +#define LOKI_THREADS_ATOMIC(x) \ + pthread_mutex_lock(&atomic_mutex_); \ + x; \ + pthread_mutex_unlock(&atomic_mutex_) + +#define LOKI_THREADS_ATOMIC_FUNCTIONS \ + private: \ + static pthread_mutex_t atomic_mutex_; \ + public: \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval *= val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval /= val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicIncrement(volatile IntType& lval) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + ++lval; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + --lval; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static void AtomicAssign(volatile IntType& lval, const IntType val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval = val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static void AtomicAssign(IntType& lval, volatile const IntType& val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval = val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + ++lval; \ + matches = ( compare == lval ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + --lval; \ + matches = ( compare == lval ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval *= val; \ + matches = ( lval == compare ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval /= val; \ + matches = ( lval == compare ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } + +#else // single threaded + +#define LOKI_THREADS_MUTEX(x) +#define LOKI_THREADS_MUTEX_INIT(x) +#define LOKI_THREADS_MUTEX_DELETE(x) +#define LOKI_THREADS_MUTEX_LOCK(x) +#define LOKI_THREADS_MUTEX_UNLOCK(x) +#define LOKI_THREADS_LONG +#define LOKI_THREADS_MUTEX_CTOR(x) + +#endif + + + +namespace Loki +{ + + //////////////////////////////////////////////////////////////////////////////// + /// \class Mutex + // + /// \ingroup ThreadingGroup + /// A simple and portable Mutex. A default policy class for locking objects. + //////////////////////////////////////////////////////////////////////////////// + + class Mutex + { + public: + Mutex() LOKI_THREADS_MUTEX_CTOR(mtx_) + { + LOKI_THREADS_MUTEX_INIT(&mtx_); + } + ~Mutex() + { + LOKI_THREADS_MUTEX_DELETE(&mtx_); + } + void Lock() + { + LOKI_THREADS_MUTEX_LOCK(&mtx_); + } + void Unlock() + { + LOKI_THREADS_MUTEX_UNLOCK(&mtx_); + } + private: + /// Copy-constructor not implemented. + Mutex(const Mutex &); + /// Copy-assignement operator not implemented. + Mutex & operator = (const Mutex &); + LOKI_THREADS_MUTEX(mtx_) + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// \class SingleThreaded + /// + /// \ingroup ThreadingGroup + /// Implementation of the ThreadingModel policy used by various classes + /// Implements a single-threaded model; no synchronization + //////////////////////////////////////////////////////////////////////////////// + template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX> + class SingleThreaded + { + public: + /// \struct Lock + /// Dummy Lock class + struct Lock + { + Lock() {} + explicit Lock(const SingleThreaded&) {} + explicit Lock(const SingleThreaded*) {} + }; + + typedef Host VolatileType; + + typedef int IntType; + + static IntType AtomicAdd(volatile IntType& lval, const IntType val) + { return lval += val; } + + static IntType AtomicSubtract(volatile IntType& lval, const IntType val) + { return lval -= val; } + + static IntType AtomicMultiply(volatile IntType& lval, const IntType val) + { return lval *= val; } + + static IntType AtomicDivide(volatile IntType& lval, const IntType val) + { return lval /= val; } + + static IntType AtomicIncrement(volatile IntType& lval) + { return ++lval; } + + static IntType AtomicDecrement(volatile IntType& lval) + { return --lval; } + + static void AtomicAssign(volatile IntType & lval, const IntType val) + { lval = val; } + + static void AtomicAssign(IntType & lval, volatile IntType & val) + { lval = val; } + + static IntType AtomicAdd(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval += val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicSubtract(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval -= val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval *= val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval /= val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) + { + ++lval; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) + { + --lval; + matches = ( lval == compare ); + return lval; + } + + }; + + +#if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H) + + //////////////////////////////////////////////////////////////////////////////// + /// \class ObjectLevelLockable + /// + /// \ingroup ThreadingGroup + /// Implementation of the ThreadingModel policy used by various classes + /// Implements a object-level locking scheme + //////////////////////////////////////////////////////////////////////////////// + template < class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX > + class ObjectLevelLockable + { + mutable MutexPolicy mtx_; + + public: + ObjectLevelLockable() : mtx_() {} + + ObjectLevelLockable(const ObjectLevelLockable&) : mtx_() {} + + ~ObjectLevelLockable() {} + + class Lock; + friend class Lock; + + /// \struct Lock + /// Lock class to lock on object level + class Lock + { + public: + + /// Lock object + explicit Lock(const ObjectLevelLockable& host) : host_(host) + { + host_.mtx_.Lock(); + } + + /// Lock object + explicit Lock(const ObjectLevelLockable* host) : host_(*host) + { + host_.mtx_.Lock(); + } + + /// Unlock object + ~Lock() + { + host_.mtx_.Unlock(); + } + + private: + /// private by design of the object level threading + Lock(); + Lock(const Lock&); + Lock& operator=(const Lock&); + const ObjectLevelLockable& host_; + }; + + typedef volatile Host VolatileType; + + typedef LOKI_THREADS_LONG IntType; + + LOKI_THREADS_ATOMIC_FUNCTIONS + + }; + +#ifdef LOKI_PTHREAD_H + template <class Host, class MutexPolicy> + pthread_mutex_t ObjectLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER; +#endif + + //////////////////////////////////////////////////////////////////////////////// + /// \class ClassLevelLockable + /// + /// \ingroup ThreadingGroup + /// Implementation of the ThreadingModel policy used by various classes + /// Implements a class-level locking scheme + //////////////////////////////////////////////////////////////////////////////// + template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX > + class ClassLevelLockable + { + struct Initializer + { + bool init_; + MutexPolicy mtx_; + + Initializer() : init_(false), mtx_() + { + init_ = true; + } + + ~Initializer() + { + assert(init_); + } + }; + + static Initializer initializer_; + + public: + + class Lock; + friend class Lock; + + /// \struct Lock + /// Lock class to lock on class level + class Lock + { + public: + + /// Lock class + Lock() + { + assert(initializer_.init_); + initializer_.mtx_.Lock(); + } + + /// Lock class + explicit Lock(const ClassLevelLockable&) + { + assert(initializer_.init_); + initializer_.mtx_.Lock(); + } + + /// Lock class + explicit Lock(const ClassLevelLockable*) + { + assert(initializer_.init_); + initializer_.mtx_.Lock(); + } + + /// Unlock class + ~Lock() + { + assert(initializer_.init_); + initializer_.mtx_.Unlock(); + } + + private: + Lock(const Lock&); + Lock& operator=(const Lock&); + }; + + typedef volatile Host VolatileType; + + typedef LOKI_THREADS_LONG IntType; + + LOKI_THREADS_ATOMIC_FUNCTIONS + + }; + +#ifdef LOKI_PTHREAD_H + template <class Host, class MutexPolicy> + pthread_mutex_t ClassLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER; +#endif + + template < class Host, class MutexPolicy > + typename ClassLevelLockable< Host, MutexPolicy >::Initializer + ClassLevelLockable< Host, MutexPolicy >::initializer_; + +#endif // #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H) + +} // namespace Loki + + +#endif // end file guardian + |