21 #if BT_USE_OPENMP && BT_THREADSAFE 25 #endif // #if BT_USE_OPENMP && BT_THREADSAFE 28 #if BT_USE_PPL && BT_THREADSAFE 35 #endif // #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> 47 #endif // #if BT_USE_TBB && BT_THREADSAFE 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));
197 #else //#elif USE_MSVC_INTRINSICS 199 #error "no threading primitives defined -- unknown platform" 201 #endif //#else //#elif USE_MSVC_INTRINSICS 203 #else //#if BT_THREADSAFE 208 btAssert( !
"unimplemented btSpinMutex::lock() called" );
213 btAssert( !
"unimplemented btSpinMutex::unlock() called" );
218 btAssert( !
"unimplemented btSpinMutex::tryLock() called" );
222 #define THREAD_LOCAL_STATIC static 224 #endif // #else //#if BT_THREADSAFE 245 btAssert( !
"thread counter exceeded" );
287 #define BT_DETECT_BAD_THREAD_INDEX 0 289 #if BT_DETECT_BAD_THREAD_INDEX 291 typedef DWORD ThreadId_t;
292 const static ThreadId_t kInvalidThreadId = 0;
295 static ThreadId_t getDebugThreadId()
297 return GetCurrentThreadId();
300 #endif // #if BT_DETECT_BAD_THREAD_INDEX 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!" );
334 #endif // #if BT_DETECT_BAD_THREAD_INDEX 406 btAssert( !
"btSetTaskScheduler must be called from the main thread!" );
433 #if BT_DETECT_BAD_THREAD_INDEX 439 gDebugThreadIds[ i ] = kInvalidThreadId;
442 #endif // #if BT_DETECT_BAD_THREAD_INDEX 447 #else // #if BT_THREADSAFE 450 btAssert( !
"called btParallelFor in non-threadsafe build. enable BT_THREADSAFE" );
453 #endif// #if 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 ) );
523 #endif // #if BT_USE_OPENMP && BT_THREADSAFE 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()
598 #endif // #if BT_USE_TBB && BT_THREADSAFE 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,
677 #endif // #if BT_USE_PPL && BT_THREADSAFE 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 * btGetPPLTaskScheduler()
void btResetThreadIndexCounter()
virtual void forLoop(int iBegin, int iEnd) const =0
virtual void parallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody &body) BT_OVERRIDE
btITaskScheduler * btGetTaskScheduler()
virtual void deactivate()
virtual int getNumThreads() const =0
btSpinMutex – lightweight spin-mutex implemented with atomic ops, never puts a thread to sleep beca...
void btPushThreadsAreRunning()
virtual int getMaxNumThreads() const BT_OVERRIDE
const unsigned int BT_MAX_THREAD_COUNT
virtual void setNumThreads(int numThreads)=0
void btSetTaskScheduler(btITaskScheduler *ts)
btTaskSchedulerSequential()
#define THREAD_LOCAL_STATIC
bool btThreadsAreRunning()
virtual void parallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody &body)=0
static ThreadsafeCounter gThreadCounter
btTaskSchedulerSequential – non-threaded implementation of task scheduler (really just useful for t...
virtual int getNumThreads() const BT_OVERRIDE
btITaskScheduler(const char *name)
virtual void setNumThreads(int numThreads) BT_OVERRIDE
static btITaskScheduler * gBtTaskScheduler
btITaskScheduler * btGetSequentialTaskScheduler()
btITaskScheduler * btGetTBBTaskScheduler()
unsigned int m_savedThreadCounter
static int gThreadsRunningCounter
void btParallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody &body)
unsigned int btGetCurrentThreadIndex()
btITaskScheduler * btGetOpenMPTaskScheduler()
static btSpinMutex gThreadsRunningCounterMutex
void btPopThreadsAreRunning()
virtual int getMaxNumThreads() const =0