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;