2013-12-09 22:56:48 +00:00
|
|
|
/*
|
2014-06-07 00:50:46 +00:00
|
|
|
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
2013-12-09 22:56:48 +00:00
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#if defined(LEAN_MULTI_THREAD)
|
2013-12-10 00:55:13 +00:00
|
|
|
#if !defined(LEAN_USE_BOOST)
|
|
|
|
// MULTI THREADING SUPPORT BASED ON THE STANDARD LIBRARY
|
2013-12-09 22:56:48 +00:00
|
|
|
#include <thread>
|
|
|
|
#include <mutex>
|
|
|
|
#include <atomic>
|
|
|
|
#include <condition_variable>
|
2013-12-10 00:55:13 +00:00
|
|
|
#include <chrono>
|
2013-12-09 22:56:48 +00:00
|
|
|
#define LEAN_THREAD_LOCAL thread_local
|
|
|
|
namespace lean {
|
2013-12-10 00:55:13 +00:00
|
|
|
inline void set_thread_stack_size(size_t ) {}
|
2013-12-09 22:56:48 +00:00
|
|
|
using std::thread;
|
|
|
|
using std::mutex;
|
2014-05-01 19:27:12 +00:00
|
|
|
using std::recursive_mutex;
|
2013-12-09 22:56:48 +00:00
|
|
|
using std::atomic;
|
|
|
|
using std::atomic_bool;
|
|
|
|
using std::atomic_ushort;
|
2014-05-12 23:14:31 +00:00
|
|
|
using std::atomic_uint;
|
2014-02-20 17:48:08 +00:00
|
|
|
using std::atomic_uchar;
|
2013-12-09 22:56:48 +00:00
|
|
|
using std::condition_variable;
|
|
|
|
using std::lock_guard;
|
|
|
|
using std::unique_lock;
|
|
|
|
using std::atomic_load;
|
|
|
|
using std::atomic_fetch_add_explicit;
|
|
|
|
using std::atomic_fetch_sub_explicit;
|
|
|
|
using std::memory_order_relaxed;
|
2014-07-21 15:22:58 +00:00
|
|
|
using std::memory_order_release;
|
|
|
|
using std::memory_order_acquire;
|
|
|
|
using std::atomic_thread_fence;
|
2013-12-10 00:55:13 +00:00
|
|
|
namespace chrono = std::chrono;
|
2013-12-09 22:56:48 +00:00
|
|
|
namespace this_thread = std::this_thread;
|
|
|
|
}
|
|
|
|
#else
|
2013-12-10 00:55:13 +00:00
|
|
|
// MULTI THREADING SUPPORT BASED ON THE BOOST LIBRARY
|
|
|
|
#include <boost/thread.hpp>
|
|
|
|
#define LEAN_THREAD_LOCAL thread_local
|
|
|
|
namespace lean {
|
|
|
|
void set_thread_stack_size(size_t );
|
|
|
|
boost::thread::attributes const & get_thread_attributes();
|
|
|
|
using boost::thread;
|
2014-06-07 15:05:19 +00:00
|
|
|
using boost::mutex;
|
2014-05-01 19:27:12 +00:00
|
|
|
using boost::recursive_mutex;
|
2013-12-10 00:55:13 +00:00
|
|
|
using boost::atomic;
|
|
|
|
using boost::memory_order_relaxed;
|
2014-07-21 15:22:58 +00:00
|
|
|
using boost::memory_order_acquire;
|
|
|
|
using boost::memory_order_release;
|
2013-12-10 00:55:13 +00:00
|
|
|
using boost::condition_variable;
|
|
|
|
using boost::unique_lock;
|
|
|
|
using boost::lock_guard;
|
2014-07-21 15:22:58 +00:00
|
|
|
using boost::atomic_thread_fence;
|
2013-12-10 00:55:13 +00:00
|
|
|
namespace chrono = boost::chrono;
|
|
|
|
namespace this_thread = boost::this_thread;
|
|
|
|
typedef atomic<bool> atomic_bool;
|
|
|
|
typedef atomic<unsigned short> atomic_ushort;
|
2014-02-20 17:48:08 +00:00
|
|
|
typedef atomic<unsigned char> atomic_uchar;
|
2014-05-12 23:14:31 +00:00
|
|
|
typedef atomic<unsigned> atomic_uint;
|
2013-12-10 00:55:13 +00:00
|
|
|
template<typename T> T atomic_load(atomic<T> const * a) { return a->load(); }
|
|
|
|
template<typename T> T atomic_fetch_add_explicit(atomic<T> * a, T v, boost::memory_order mo) { return a->fetch_add(v, mo); }
|
|
|
|
template<typename T> T atomic_fetch_sub_explicit(atomic<T> * a, T v, boost::memory_order mo) { return a->fetch_sub(v, mo); }
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
// NO MULTI THREADING SUPPORT
|
2013-12-09 22:56:48 +00:00
|
|
|
#include <utility>
|
2013-12-10 00:55:13 +00:00
|
|
|
#include <cstdlib>
|
2013-12-09 22:56:48 +00:00
|
|
|
#define LEAN_THREAD_LOCAL
|
|
|
|
namespace lean {
|
2013-12-10 00:55:13 +00:00
|
|
|
inline void set_thread_stack_size(size_t ) {}
|
|
|
|
namespace chrono {
|
|
|
|
typedef unsigned milliseconds;
|
|
|
|
}
|
2013-12-09 22:56:48 +00:00
|
|
|
constexpr int memory_order_relaxed = 0;
|
2014-07-21 15:22:58 +00:00
|
|
|
constexpr int memory_order_release = 0;
|
|
|
|
constexpr int memory_order_acquire = 0;
|
|
|
|
inline void atomic_thread_fence(int ) {}
|
2013-12-09 22:56:48 +00:00
|
|
|
template<typename T>
|
|
|
|
class atomic {
|
|
|
|
T m_value;
|
|
|
|
public:
|
|
|
|
atomic(T const & v = T()):m_value(v) {}
|
|
|
|
atomic(T && v):m_value(std::forward<T>(v)) {}
|
|
|
|
atomic(atomic const & v):m_value(v.m_value) {}
|
|
|
|
atomic(atomic && v):m_value(std::forward<T>(v.m_value)) {}
|
|
|
|
atomic & operator=(T const & v) { m_value = v; return *this; }
|
|
|
|
atomic & operator=(T && v) { m_value = std::forward<T>(v); return *this; }
|
|
|
|
atomic & operator=(atomic const & v) { m_value = v.m_value; return *this; }
|
|
|
|
atomic & operator=(atomic && v) { m_value = std::forward<T>(v.m_value); return *this; }
|
|
|
|
operator T() const { return m_value; }
|
|
|
|
void store(T const & v) { m_value = v; }
|
|
|
|
T load() const { return m_value; }
|
|
|
|
atomic & operator|=(T const & v) { m_value |= v; return *this; }
|
|
|
|
atomic & operator+=(T const & v) { m_value += v; return *this; }
|
|
|
|
atomic & operator-=(T const & v) { m_value -= v; return *this; }
|
|
|
|
atomic & operator++() { ++m_value; return *this; }
|
|
|
|
atomic operator++(int ) { atomic tmp(*this); ++m_value; return tmp; }
|
|
|
|
atomic & operator--() { --m_value; return *this; }
|
|
|
|
atomic operator--(int ) { atomic tmp(*this); --m_value; return tmp; }
|
|
|
|
friend T atomic_load(atomic const * a) { return a->m_value; }
|
|
|
|
friend T atomic_fetch_add_explicit(atomic * a, T const & v, int ) { T r(a->m_value); a->m_value += v; return r; }
|
|
|
|
friend T atomic_fetch_sub_explicit(atomic * a, T const & v, int ) { T r(a->m_value); a->m_value -= v; return r; }
|
|
|
|
};
|
|
|
|
typedef atomic<unsigned short> atomic_ushort;
|
2014-02-20 17:48:08 +00:00
|
|
|
typedef atomic<unsigned char> atomic_uchar;
|
2013-12-09 22:56:48 +00:00
|
|
|
typedef atomic<bool> atomic_bool;
|
2014-05-12 23:14:31 +00:00
|
|
|
typedef atomic<unsigned> atomic_uint;
|
2013-12-09 22:56:48 +00:00
|
|
|
class thread {
|
|
|
|
public:
|
|
|
|
thread() {}
|
|
|
|
template<typename Function, typename... Args>
|
|
|
|
thread(Function && fun, Args &&... args) {
|
|
|
|
fun(std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
typedef unsigned id;
|
|
|
|
bool joinable() const { return true; }
|
|
|
|
void join() {}
|
|
|
|
};
|
|
|
|
class this_thread {
|
|
|
|
public:
|
2013-12-10 00:55:13 +00:00
|
|
|
static void sleep_for(chrono::milliseconds const &) {}
|
2013-12-09 22:56:48 +00:00
|
|
|
static thread::id get_id() { return 0; }
|
|
|
|
static void yield() {}
|
|
|
|
};
|
|
|
|
class mutex {
|
|
|
|
public:
|
|
|
|
void lock() {}
|
|
|
|
void unlock() {}
|
|
|
|
};
|
2014-05-01 19:27:12 +00:00
|
|
|
class recursive_mutex {
|
|
|
|
public:
|
|
|
|
void lock() {}
|
|
|
|
void unlock() {}
|
|
|
|
};
|
2013-12-09 22:56:48 +00:00
|
|
|
class condition_variable {
|
|
|
|
public:
|
|
|
|
template<typename Lock> void wait(Lock const &) {}
|
|
|
|
void notify_all() {}
|
|
|
|
void notify_one() {}
|
|
|
|
};
|
|
|
|
template<typename T> class lock_guard {
|
|
|
|
public:
|
|
|
|
lock_guard(T const &) {}
|
2014-06-07 00:50:46 +00:00
|
|
|
~lock_guard() {}
|
2013-12-09 22:56:48 +00:00
|
|
|
};
|
|
|
|
template<typename T> class unique_lock {
|
|
|
|
public:
|
|
|
|
unique_lock(T const &) {}
|
2014-06-07 00:50:46 +00:00
|
|
|
~unique_lock() {}
|
2013-12-09 22:56:48 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
2014-06-07 15:16:20 +00:00
|
|
|
|
|
|
|
// LEAN_THREAD_PTR macro
|
|
|
|
#if defined(LEAN_USE_BOOST)
|
|
|
|
#include <boost/thread/tss.hpp>
|
|
|
|
#define LEAN_THREAD_PTR(T) static boost::thread_specific_ptr<T>
|
|
|
|
#else
|
2014-06-07 17:18:32 +00:00
|
|
|
template<typename T>
|
|
|
|
class thread_specific_ptr {
|
|
|
|
T * m_ptr;
|
|
|
|
public:
|
|
|
|
thread_specific_ptr():m_ptr(nullptr) {}
|
2014-07-22 17:50:04 +00:00
|
|
|
~thread_specific_ptr() { if (m_ptr) delete m_ptr; m_ptr = nullptr; }
|
2014-06-07 17:18:32 +00:00
|
|
|
T * get() const { return m_ptr; }
|
|
|
|
void reset(T * ptr) { if (m_ptr) delete m_ptr; m_ptr = ptr; }
|
|
|
|
T * operator->() const { return m_ptr; }
|
|
|
|
T & operator*() { return *m_ptr; }
|
|
|
|
};
|
|
|
|
#define LEAN_THREAD_PTR(T) static thread_specific_ptr<T> LEAN_THREAD_LOCAL
|
2014-06-07 15:16:20 +00:00
|
|
|
#endif
|
2014-06-07 17:18:32 +00:00
|
|
|
|
2014-06-07 18:34:30 +00:00
|
|
|
#if defined(LEAN_USE_BOOST) && defined(LEAN_MULTI_THREAD)
|
2014-06-07 19:15:40 +00:00
|
|
|
#define MK_THREAD_LOCAL_GET(T, GETTER_NAME, DEF_VALUE) \
|
|
|
|
LEAN_THREAD_PTR(T) GETTER_NAME ## _tlocal; \
|
|
|
|
static T & GETTER_NAME() { \
|
|
|
|
if (!(GETTER_NAME ## _tlocal).get()) \
|
|
|
|
(GETTER_NAME ## _tlocal).reset(new T(DEF_VALUE)); \
|
|
|
|
return *(GETTER_NAME ## _tlocal); \
|
2014-06-07 17:18:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-07 19:15:40 +00:00
|
|
|
#define MK_THREAD_LOCAL_GET_DEF(T, GETTER_NAME) \
|
|
|
|
LEAN_THREAD_PTR(T) GETTER_NAME ## _tlocal; \
|
|
|
|
static T & GETTER_NAME() { \
|
|
|
|
if (!(GETTER_NAME ## _tlocal).get()) \
|
|
|
|
(GETTER_NAME ## _tlocal).reset(new T()); \
|
|
|
|
return *(GETTER_NAME ## _tlocal); \
|
2014-06-07 17:18:32 +00:00
|
|
|
}
|
2014-06-07 17:41:17 +00:00
|
|
|
#else
|
2014-06-07 18:34:30 +00:00
|
|
|
// MK_THREAD_LOCAL_GET_DEF and MK_THREAD_LOCAL_GET when LEAN_USE_BOOST is not defined
|
|
|
|
// REMARK: LEAN_THREAD_LOCAL is a 'blank' when LEAN_MULTI_THREAD is not defined.
|
|
|
|
// So, the getter is just returning a reference to a global variable if LEAN_MULTI_THREAD is not defined.
|
|
|
|
#define MK_THREAD_LOCAL_GET(T, GETTER_NAME, DEF_VALUE) static T & GETTER_NAME() { static T LEAN_THREAD_LOCAL r(DEF_VALUE); return r; }
|
|
|
|
#define MK_THREAD_LOCAL_GET_DEF(T, GETTER_NAME) static T & GETTER_NAME() { static T LEAN_THREAD_LOCAL r; return r; }
|
2014-06-07 17:41:17 +00:00
|
|
|
#endif
|