21#if BT_USE_OPENMP && BT_THREADSAFE
28#if BT_USE_PPL && BT_THREADSAFE
38#if BT_USE_TBB && BT_THREADSAFE
41#define __TBB_NO_IMPLICIT_LINKAGE 1
43#include <tbb/task_scheduler_init.h>
44#include <tbb/parallel_for.h>
45#include <tbb/blocked_range.h>
58#if __cplusplus >= 201103L
62#define USE_CPP11_ATOMICS 1
64#elif defined( _MSC_VER )
67#define USE_MSVC_INTRINSICS 1
69#elif defined( __GNUC__ ) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
73#define USE_GCC_BUILTIN_ATOMICS 1
75#elif defined( __GNUC__ ) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
78#define USE_GCC_BUILTIN_ATOMICS_OLD 1
88#define THREAD_LOCAL_STATIC thread_local static
92 std::atomic<int>* aDest =
reinterpret_cast<std::atomic<int>*
>(&
mLock);
94 return std::atomic_compare_exchange_weak_explicit( aDest, &expected,
int(1), std::memory_order_acq_rel, std::memory_order_acquire );
108 std::atomic<int>* aDest =
reinterpret_cast<std::atomic<int>*
>(&
mLock);
109 std::atomic_store_explicit( aDest,
int(0), std::memory_order_release );
113#elif USE_MSVC_INTRINSICS
115#define WIN32_LEAN_AND_MEAN
120#define THREAD_LOCAL_STATIC __declspec( thread ) static
125 volatile long* aDest =
reinterpret_cast<long*
>(&
mLock);
126 return ( 0 == _InterlockedCompareExchange( aDest, 1, 0) );
140 volatile long* aDest =
reinterpret_cast<long*
>( &
mLock );
141 _InterlockedExchange( aDest, 0 );
144#elif USE_GCC_BUILTIN_ATOMICS
146#define THREAD_LOCAL_STATIC static __thread
153 const int memOrderSuccess = __ATOMIC_ACQ_REL;
154 const int memOrderFail = __ATOMIC_ACQUIRE;
155 return __atomic_compare_exchange_n(&
mLock, &expected,
int(1), weak, memOrderSuccess, memOrderFail);
169 __atomic_store_n(&
mLock,
int(0), __ATOMIC_RELEASE);
172#elif USE_GCC_BUILTIN_ATOMICS_OLD
175#define THREAD_LOCAL_STATIC static __thread
179 return __sync_bool_compare_and_swap(&
mLock,
int(0),
int(1));
194 __sync_fetch_and_and(&
mLock,
int(0));
199#error "no threading primitives defined -- unknown platform"
208 btAssert( !
"unimplemented btSpinMutex::lock() called" );
213 btAssert( !
"unimplemented btSpinMutex::unlock() called" );
218 btAssert( !
"unimplemented btSpinMutex::tryLock() called" );
222#define THREAD_LOCAL_STATIC static
245 btAssert( !
"thread counter exceeded" );
287#define BT_DETECT_BAD_THREAD_INDEX 0
289#if BT_DETECT_BAD_THREAD_INDEX
291typedef DWORD ThreadId_t;
292const static ThreadId_t kInvalidThreadId = 0;
295static ThreadId_t getDebugThreadId()
297 return GetCurrentThreadId();
306 const unsigned int kNullIndex = ~0
U;
308 if ( sThreadIndex == kNullIndex )
313#if BT_DETECT_BAD_THREAD_INDEX
316 ThreadId_t tid = getDebugThreadId();
318 if ( gDebugThreadIds[ sThreadIndex ] == kInvalidThreadId )
321 gDebugThreadIds[ sThreadIndex ] = tid;
325 if ( gDebugThreadIds[ sThreadIndex ] != tid )
329 btAssert( !
"there are 2 or more threads with the same thread-index!" );
406 btAssert( !
"btSetTaskScheduler must be called from the main thread!" );
433#if BT_DETECT_BAD_THREAD_INDEX
439 gDebugThreadIds[ i ] = kInvalidThreadId;
450 btAssert( !
"called btParallelFor in non-threadsafe build. enable BT_THREADSAFE" );
471 body.forLoop( iBegin, iEnd );
476#if BT_USE_OPENMP && BT_THREADSAFE
490 return omp_get_max_threads();
502 omp_set_num_threads( 1 );
503 omp_set_num_threads( m_numThreads );
504 m_savedThreadCounter = 0;
514#pragma omp parallel for schedule( static, 1 )
515 for (
int i = iBegin; i < iEnd; i += grainSize )
518 body.forLoop( i, ( std::min )( i + grainSize, iEnd ) );
526#if BT_USE_TBB && BT_THREADSAFE
533 tbb::task_scheduler_init* m_tbbSchedulerInit;
539 m_tbbSchedulerInit = NULL;
541 ~btTaskSchedulerTBB()
543 if ( m_tbbSchedulerInit )
545 delete m_tbbSchedulerInit;
546 m_tbbSchedulerInit = NULL;
552 return tbb::task_scheduler_init::default_num_threads();
561 if ( m_tbbSchedulerInit )
564 delete m_tbbSchedulerInit;
565 m_tbbSchedulerInit = NULL;
567 m_tbbSchedulerInit =
new tbb::task_scheduler_init( m_numThreads );
568 m_savedThreadCounter = 0;
578 void operator()(
const tbb::blocked_range<int>& range )
const
581 mBody->
forLoop( range.begin(), range.end() );
589 tbbBody.mBody = &body;
591 tbb::parallel_for( tbb::blocked_range<int>( iBegin, iEnd, grainSize ),
593 tbb::simple_partitioner()
601#if BT_USE_PPL && BT_THREADSAFE
615 return concurrency::GetProcessorCount();
625 m_numThreads = ( std::max )( 1, ( std::min )( maxThreadCount, numThreads ) );
626 using namespace concurrency;
627 if ( CurrentScheduler::Id() != -1 )
629 CurrentScheduler::Detach();
631 SchedulerPolicy policy;
635 policy.SetConcurrencyLimits( 1, 1 );
636 CurrentScheduler::Create( policy );
637 CurrentScheduler::Detach();
639 policy.SetConcurrencyLimits( m_numThreads, m_numThreads );
640 CurrentScheduler::Create( policy );
641 m_savedThreadCounter = 0;
653 void operator()(
int i )
const
656 mBody->
forLoop( i, ( std::min )( i + mGrainSize, mIndexEnd ) );
664 pplBody.mBody = &body;
665 pplBody.mGrainSize = grainSize;
666 pplBody.mIndexEnd = iEnd;
669 concurrency::parallel_for( iBegin,
684 return &sTaskScheduler;
691#if BT_USE_OPENMP && BT_THREADSAFE
692 static btTaskSchedulerOpenMP sTaskScheduler;
693 return &sTaskScheduler;
703#if BT_USE_TBB && BT_THREADSAFE
704 static btTaskSchedulerTBB sTaskScheduler;
705 return &sTaskScheduler;
715#if BT_USE_PPL && BT_THREADSAFE
716 static btTaskSchedulerPPL sTaskScheduler;
717 return &sTaskScheduler;
btITaskScheduler * btGetTBBTaskScheduler()
void btPopThreadsAreRunning()
btITaskScheduler * btGetPPLTaskScheduler()
void btResetThreadIndexCounter()
static btITaskScheduler * gBtTaskScheduler
static btSpinMutex gThreadsRunningCounterMutex
bool btThreadsAreRunning()
void btPushThreadsAreRunning()
static int gThreadsRunningCounter
btITaskScheduler * btGetOpenMPTaskScheduler()
unsigned int btGetCurrentThreadIndex()
static ThreadsafeCounter gThreadCounter
void btSetTaskScheduler(btITaskScheduler *ts)
btITaskScheduler * btGetTaskScheduler()
btITaskScheduler * btGetSequentialTaskScheduler()
#define THREAD_LOCAL_STATIC
void btParallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody &body)
const unsigned int BT_MAX_THREAD_COUNT
virtual void forLoop(int iBegin, int iEnd) const =0
btITaskScheduler(const char *name)
virtual int getNumThreads() const =0
unsigned int m_savedThreadCounter
virtual int getMaxNumThreads() const =0
virtual void parallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody &body)=0
virtual void deactivate()
virtual void setNumThreads(int numThreads)=0
btSpinMutex – lightweight spin-mutex implemented with atomic ops, never puts a thread to sleep becaus...
btTaskSchedulerSequential – non-threaded implementation of task scheduler (really just useful for tes...
virtual void setNumThreads(int numThreads) BT_OVERRIDE
virtual int getMaxNumThreads() const BT_OVERRIDE
virtual int getNumThreads() const BT_OVERRIDE
btTaskSchedulerSequential()
virtual void parallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody &body) BT_OVERRIDE