$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 #ifndef LIBMESH_THREADS_H 00020 #define LIBMESH_THREADS_H 00021 00022 // Local includes 00023 #include "libmesh/libmesh_config.h" 00024 #include "libmesh/libmesh_common.h" // for libmesh_assert 00025 00026 // Threading building blocks includes 00027 #ifdef LIBMESH_HAVE_TBB_API 00028 # include "libmesh/libmesh_logging.h" // only mess with the perflog if we are really multithreaded 00029 # include "tbb/tbb_stddef.h" 00030 # include "tbb/blocked_range.h" 00031 # include "tbb/parallel_for.h" 00032 # include "tbb/parallel_reduce.h" 00033 # include "tbb/task_scheduler_init.h" 00034 # include "tbb/partitioner.h" 00035 # include "tbb/spin_mutex.h" 00036 # include "tbb/recursive_mutex.h" 00037 // include "boost/thread/recursive_mutex.hpp" 00038 # include "tbb/atomic.h" 00039 #endif 00040 00041 // C++ includes 00042 #ifdef LIBMESH_HAVE_STD_THREAD 00043 # include <thread> 00044 #elif LIBMESH_HAVE_TBB_CXX_THREAD 00045 # include "tbb/tbb_thread.h" 00046 #endif 00047 00048 #ifdef LIBMESH_HAVE_PTHREAD 00049 # include "libmesh/libmesh_logging.h" // only mess with the perflog if we are really multithreaded 00050 # include <pthread.h> 00051 # include <algorithm> 00052 # include <vector> 00053 00054 #ifdef __APPLE__ 00055 #include <libkern/OSAtomic.h> 00056 #endif 00057 00058 #endif 00059 00060 // Thread-Local-Storage macros 00061 00062 #ifdef LIBMESH_HAVE_STD_THREAD 00063 # define LIBMESH_TLS_TYPE(type) thread_local type 00064 # define LIBMESH_TLS_REF(value) (value) 00065 #else 00066 # ifdef LIBMESH_HAVE_TBB_API 00067 # include "tbb/enumerable_thread_specific.h" 00068 # define LIBMESH_TLS_TYPE(type) tbb::enumerable_thread_specific<type> 00069 # define LIBMESH_TLS_REF(value) (value).local() 00070 # else // Maybe support gcc __thread eventually? 00071 # define LIBMESH_TLS_TYPE(type) type 00072 # define LIBMESH_TLS_REF(value) (value) 00073 # endif 00074 #endif 00075 00076 00077 00078 namespace libMesh 00079 { 00080 00081 00086 namespace Threads 00087 { 00093 extern bool in_threads; 00094 00099 class BoolAcquire { 00100 public: 00101 explicit 00102 BoolAcquire(bool& b) : _b(b) { libmesh_assert(!_b); _b = true; } 00103 00104 ~BoolAcquire() { libmesh_exceptionless_assert(_b); _b = false; } 00105 private: 00106 bool& _b; 00107 }; 00108 00109 00110 #ifdef LIBMESH_HAVE_STD_THREAD 00111 //-------------------------------------------------------------------- 00115 typedef std::thread Thread; 00116 00117 #elif LIBMESH_HAVE_TBB_CXX_THREAD 00118 //-------------------------------------------------------------------- 00122 typedef tbb::tbb_thread Thread; 00123 00124 #else 00125 //-------------------------------------------------------------------- 00130 class Thread 00131 { 00132 public: 00138 template <typename Callable> 00139 Thread (Callable f) { f(); } 00140 00144 void join() {} 00145 00149 bool joinable() const { return true; } 00150 }; 00151 00152 #endif 00153 00154 00155 00156 #ifdef LIBMESH_HAVE_TBB_API 00157 //------------------------------------------------------------------- 00161 typedef tbb::task_scheduler_init task_scheduler_init; 00162 00163 00164 00165 //------------------------------------------------------------------- 00170 typedef tbb::split split; 00171 00172 00173 00174 //------------------------------------------------------------------- 00179 template <typename Range, typename Body> 00180 inline 00181 void parallel_for (const Range &range, const Body &body) 00182 { 00183 BoolAcquire b(in_threads); 00184 00185 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00186 const bool logging_was_enabled = libMesh::perflog.logging_enabled(); 00187 00188 if (libMesh::n_threads() > 1) 00189 libMesh::perflog.disable_logging(); 00190 #endif 00191 00192 if (libMesh::n_threads() > 1) 00193 tbb::parallel_for (range, body, tbb::auto_partitioner()); 00194 00195 else 00196 body(range); 00197 00198 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00199 if (libMesh::n_threads() > 1 && logging_was_enabled) 00200 libMesh::perflog.enable_logging(); 00201 #endif 00202 } 00203 00204 00205 00206 //------------------------------------------------------------------- 00211 template <typename Range, typename Body, typename Partitioner> 00212 inline 00213 void parallel_for (const Range &range, const Body &body, const Partitioner &partitioner) 00214 { 00215 BoolAcquire b(in_threads); 00216 00217 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00218 const bool logging_was_enabled = libMesh::perflog.logging_enabled(); 00219 00220 if (libMesh::n_threads() > 1) 00221 libMesh::perflog.disable_logging(); 00222 #endif 00223 00224 if (libMesh::n_threads() > 1) 00225 tbb::parallel_for (range, body, partitioner); 00226 00227 else 00228 body(range); 00229 00230 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00231 if (libMesh::n_threads() > 1 && logging_was_enabled) 00232 libMesh::perflog.enable_logging(); 00233 #endif 00234 } 00235 00236 00237 00238 //------------------------------------------------------------------- 00243 template <typename Range, typename Body> 00244 inline 00245 void parallel_reduce (const Range &range, Body &body) 00246 { 00247 BoolAcquire b(in_threads); 00248 00249 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00250 const bool logging_was_enabled = libMesh::perflog.logging_enabled(); 00251 00252 if (libMesh::n_threads() > 1) 00253 libMesh::perflog.disable_logging(); 00254 #endif 00255 00256 if (libMesh::n_threads() > 1) 00257 tbb::parallel_reduce (range, body, tbb::auto_partitioner()); 00258 00259 else 00260 body(range); 00261 00262 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00263 if (libMesh::n_threads() > 1 && logging_was_enabled) 00264 libMesh::perflog.enable_logging(); 00265 #endif 00266 } 00267 00268 00269 00270 //------------------------------------------------------------------- 00275 template <typename Range, typename Body, typename Partitioner> 00276 inline 00277 void parallel_reduce (const Range &range, Body &body, const Partitioner &partitioner) 00278 { 00279 BoolAcquire b(in_threads); 00280 00281 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00282 const bool logging_was_enabled = libMesh::perflog.logging_enabled(); 00283 00284 if (libMesh::n_threads() > 1) 00285 libMesh::perflog.disable_logging(); 00286 #endif 00287 00288 if (libMesh::n_threads() > 1) 00289 tbb::parallel_reduce (range, body, partitioner); 00290 00291 else 00292 body(range); 00293 00294 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00295 if (libMesh::n_threads() > 1 && logging_was_enabled) 00296 libMesh::perflog.enable_logging(); 00297 #endif 00298 } 00299 00300 00301 00302 //------------------------------------------------------------------- 00307 typedef tbb::spin_mutex spin_mutex; 00308 00309 //------------------------------------------------------------------- 00315 typedef tbb::recursive_mutex recursive_mutex; 00316 00317 //------------------------------------------------------------------- 00323 template <typename T> 00324 class atomic : public tbb::atomic<T> {}; 00325 00326 #else //LIBMESH_HAVE_TBB_API 00327 #ifdef LIBMESH_HAVE_PTHREAD 00328 00329 //------------------------------------------------------------------- 00334 #ifdef __APPLE__ 00335 class spin_mutex 00336 { 00337 public: 00338 spin_mutex() : slock(0) {} // The convention is that the lock being zero is _unlocked_ 00339 ~spin_mutex() {} 00340 00341 void lock () { OSSpinLockLock(&slock); } 00342 void unlock () { OSSpinLockUnlock(&slock); } 00343 00344 class scoped_lock 00345 { 00346 public: 00347 scoped_lock () : smutex(NULL) {} 00348 explicit scoped_lock ( spin_mutex& in_smutex ) : smutex(&in_smutex) { smutex->lock(); } 00349 00350 ~scoped_lock () { release(); } 00351 00352 void acquire ( spin_mutex& in_smutex ) { smutex = &in_smutex; smutex->lock(); } 00353 void release () { if(smutex) smutex->unlock(); smutex = NULL; } 00354 00355 private: 00356 spin_mutex * smutex; 00357 }; 00358 00359 private: 00360 OSSpinLock slock; 00361 }; 00362 #else 00363 class spin_mutex 00364 { 00365 public: 00366 // Might want to use PTHREAD_MUTEX_ADAPTIVE_NP on Linux, but it's not available on OSX. 00367 spin_mutex() { pthread_spin_init(&slock, PTHREAD_PROCESS_PRIVATE); } 00368 ~spin_mutex() { pthread_spin_destroy(&slock); } 00369 00370 void lock () { pthread_spin_lock(&slock); } 00371 void unlock () { pthread_spin_unlock(&slock); } 00372 00373 class scoped_lock 00374 { 00375 public: 00376 scoped_lock () : smutex(NULL) {} 00377 explicit scoped_lock ( spin_mutex& in_smutex ) : smutex(&in_smutex) { smutex->lock(); } 00378 00379 ~scoped_lock () { release(); } 00380 00381 void acquire ( spin_mutex& in_smutex ) { smutex = &in_smutex; smutex->lock(); } 00382 void release () { if(smutex) smutex->unlock(); smutex = NULL; } 00383 00384 private: 00385 spin_mutex * smutex; 00386 }; 00387 00388 private: 00389 pthread_spinlock_t slock; 00390 }; 00391 #endif 00392 00393 //------------------------------------------------------------------- 00398 class recursive_mutex 00399 { 00400 public: 00401 // Might want to use PTHREAD_MUTEX_ADAPTIVE_NP on Linux, but it's not available on OSX. 00402 recursive_mutex() 00403 { 00404 pthread_mutexattr_init(&attr); 00405 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 00406 pthread_mutex_init(&mutex, &attr); 00407 } 00408 ~recursive_mutex() { pthread_mutex_destroy(&mutex); } 00409 00410 void lock () { pthread_mutex_lock(&mutex); } 00411 void unlock () { pthread_mutex_unlock(&mutex); } 00412 00413 class scoped_lock 00414 { 00415 public: 00416 scoped_lock () : rmutex(NULL) {} 00417 explicit scoped_lock ( recursive_mutex& in_rmutex ) : rmutex(&in_rmutex) { rmutex->lock(); } 00418 00419 ~scoped_lock () { release(); } 00420 00421 void acquire ( recursive_mutex& in_rmutex ) { rmutex = &in_rmutex; rmutex->lock(); } 00422 void release () { if(rmutex) rmutex->unlock(); rmutex = NULL; } 00423 00424 private: 00425 recursive_mutex * rmutex; 00426 }; 00427 00428 private: 00429 pthread_mutex_t mutex; 00430 pthread_mutexattr_t attr; 00431 }; 00432 00433 extern std::map<pthread_t, unsigned int> _pthread_unique_ids; 00434 extern spin_mutex _pthread_unique_id_mutex; 00435 00440 unsigned int pthread_unique_id(); 00441 00442 template <typename Range> 00443 unsigned int num_pthreads(Range & range) 00444 { 00445 unsigned int min = std::min((std::size_t)libMesh::n_threads(), range.size()); 00446 return min > 0 ? min : 1; 00447 } 00448 00449 template <typename Range, typename Body> 00450 class RangeBody 00451 { 00452 public: 00453 Range * range; 00454 Body * body; 00455 }; 00456 00457 template <typename Range, typename Body> 00458 void * run_body(void * args) 00459 { 00460 00461 RangeBody<Range, Body> * range_body = (RangeBody<Range, Body>*)args; 00462 00463 Body & body = *range_body->body; 00464 Range & range = *range_body->range; 00465 00466 body(range); 00467 00468 return NULL; 00469 } 00470 00471 //------------------------------------------------------------------- 00475 class task_scheduler_init 00476 { 00477 public: 00478 static const int automatic = -1; 00479 explicit task_scheduler_init (int = automatic) {} 00480 void initialize (int = automatic) {} 00481 void terminate () {} 00482 }; 00483 00484 //------------------------------------------------------------------- 00489 class split {}; 00490 00491 00492 00493 00494 //------------------------------------------------------------------- 00499 template <typename Range, typename Body> 00500 inline 00501 void parallel_for (const Range &range, const Body &body) 00502 { 00503 Threads::BoolAcquire b(Threads::in_threads); 00504 00505 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00506 const bool logging_was_enabled = libMesh::perflog.logging_enabled(); 00507 00508 if (libMesh::n_threads() > 1) 00509 libMesh::perflog.disable_logging(); 00510 #endif 00511 00512 unsigned int n_threads = num_pthreads(range); 00513 00514 std::vector<Range *> ranges(n_threads); 00515 std::vector<RangeBody<const Range, const Body> > range_bodies(n_threads); 00516 std::vector<pthread_t> threads(n_threads); 00517 00518 // Create the ranges for each thread 00519 unsigned int range_size = range.size() / n_threads; 00520 00521 typename Range::const_iterator current_beginning = range.begin(); 00522 00523 for(unsigned int i=0; i<n_threads; i++) 00524 { 00525 unsigned int this_range_size = range_size; 00526 00527 if(i+1 == n_threads) 00528 this_range_size += range.size() % n_threads; // Give the last one the remaining work to do 00529 00530 ranges[i] = new Range(range, current_beginning, current_beginning + this_range_size); 00531 00532 current_beginning = current_beginning + this_range_size; 00533 } 00534 00535 // Create the RangeBody arguments 00536 for(unsigned int i=0; i<n_threads; i++) 00537 { 00538 range_bodies[i].range = ranges[i]; 00539 range_bodies[i].body = &body; 00540 } 00541 00542 // Create the threads 00543 #pragma omp parallel for schedule (static) 00544 for(unsigned int i=0; i<n_threads; i++) 00545 { 00546 #if LIBMESH_HAVE_OPENMP 00547 run_body<Range, Body>((void*)&range_bodies[i]); 00548 #else // Just use Pthreads 00549 spin_mutex::scoped_lock lock(_pthread_unique_id_mutex); 00550 pthread_create(&threads[i], NULL, &run_body<Range, Body>, (void*)&range_bodies[i]); 00551 _pthread_unique_ids[threads[i]] = i; 00552 #endif 00553 } 00554 00555 #if !LIBMESH_HAVE_OPENMP 00556 // Wait for them to finish 00557 00558 // The use of 'int' instead of unsigned for the iteration variable 00559 // is deliberate here. This is an OpenMP loop, and some older 00560 // compilers warn when you don't use int for the loop index. The 00561 // reason has to do with signed vs. unsigned integer overflow 00562 // behavior and optimization. 00563 // http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html 00564 for (int i=0; i<static_cast<int>(n_threads); i++) 00565 { 00566 pthread_join(threads[i], NULL); 00567 spin_mutex::scoped_lock lock(_pthread_unique_id_mutex); 00568 _pthread_unique_ids.erase(threads[i]); 00569 } 00570 #endif 00571 00572 // Clean up 00573 for(unsigned int i=0; i<n_threads; i++) 00574 delete ranges[i]; 00575 00576 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00577 if (libMesh::n_threads() > 1 && logging_was_enabled) 00578 libMesh::perflog.enable_logging(); 00579 #endif 00580 } 00581 00582 //------------------------------------------------------------------- 00587 template <typename Range, typename Body, typename Partitioner> 00588 inline 00589 void parallel_for (const Range &range, const Body &body, const Partitioner &) 00590 { 00591 parallel_for(range, body); 00592 } 00593 00594 //------------------------------------------------------------------- 00599 template <typename Range, typename Body> 00600 inline 00601 void parallel_reduce (const Range &range, Body &body) 00602 { 00603 Threads::BoolAcquire b(Threads::in_threads); 00604 00605 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00606 const bool logging_was_enabled = libMesh::perflog.logging_enabled(); 00607 00608 if (libMesh::n_threads() > 1) 00609 libMesh::perflog.disable_logging(); 00610 #endif 00611 00612 unsigned int n_threads = num_pthreads(range); 00613 00614 std::vector<Range *> ranges(n_threads); 00615 std::vector<Body *> bodies(n_threads); 00616 std::vector<RangeBody<Range, Body> > range_bodies(n_threads); 00617 00618 // Create copies of the body for each thread 00619 bodies[0] = &body; // Use the original body for the first one 00620 for(unsigned int i=1; i<n_threads; i++) 00621 bodies[i] = new Body(body, Threads::split()); 00622 00623 // Create the ranges for each thread 00624 unsigned int range_size = range.size() / n_threads; 00625 00626 typename Range::const_iterator current_beginning = range.begin(); 00627 00628 for(unsigned int i=0; i<n_threads; i++) 00629 { 00630 unsigned int this_range_size = range_size; 00631 00632 if(i+1 == n_threads) 00633 this_range_size += range.size() % n_threads; // Give the last one the remaining work to do 00634 00635 ranges[i] = new Range(range, current_beginning, current_beginning + this_range_size); 00636 00637 current_beginning = current_beginning + this_range_size; 00638 } 00639 00640 // Create the RangeBody arguments 00641 for(unsigned int i=0; i<n_threads; i++) 00642 { 00643 range_bodies[i].range = ranges[i]; 00644 range_bodies[i].body = bodies[i]; 00645 } 00646 00647 // Create the threads 00648 std::vector<pthread_t> threads(n_threads); 00649 00650 #pragma omp parallel for schedule (static) 00651 // The use of 'int' instead of unsigned for the iteration variable 00652 // is deliberate here. This is an OpenMP loop, and some older 00653 // compilers warn when you don't use int for the loop index. The 00654 // reason has to do with signed vs. unsigned integer overflow 00655 // behavior and optimization. 00656 // http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html 00657 for (int i=0; i<static_cast<int>(n_threads); i++) 00658 { 00659 #if LIBMESH_HAVE_OPENMP 00660 run_body<Range, Body>((void*)&range_bodies[i]); 00661 #else // Just use Pthreads 00662 spin_mutex::scoped_lock lock(_pthread_unique_id_mutex); 00663 pthread_create(&threads[i], NULL, &run_body<Range, Body>, (void*)&range_bodies[i]); 00664 _pthread_unique_ids[threads[i]] = i; 00665 #endif 00666 } 00667 00668 #if !LIBMESH_HAVE_OPENMP 00669 // Wait for them to finish 00670 for(unsigned int i=0; i<n_threads; i++) 00671 { 00672 pthread_join(threads[i], NULL); 00673 spin_mutex::scoped_lock lock(_pthread_unique_id_mutex); 00674 _pthread_unique_ids.erase(threads[i]); 00675 } 00676 #endif 00677 00678 // Join them all down to the original Body 00679 for(unsigned int i=n_threads-1; i != 0; i--) 00680 bodies[i-1]->join(*bodies[i]); 00681 00682 // Clean up 00683 for(unsigned int i=1; i<n_threads; i++) 00684 delete bodies[i]; 00685 for(unsigned int i=0; i<n_threads; i++) 00686 delete ranges[i]; 00687 00688 #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING 00689 if (libMesh::n_threads() > 1 && logging_was_enabled) 00690 libMesh::perflog.enable_logging(); 00691 #endif 00692 } 00693 00694 //------------------------------------------------------------------- 00699 template <typename Range, typename Body, typename Partitioner> 00700 inline 00701 void parallel_reduce (const Range &range, Body &body, const Partitioner &) 00702 { 00703 parallel_reduce(range, body); 00704 } 00705 00706 00707 //------------------------------------------------------------------- 00712 template <typename T> 00713 class atomic 00714 { 00715 public: 00716 atomic () : val(0) {} 00717 operator T () { return val; } 00718 00719 T operator=( T value ) 00720 { 00721 spin_mutex::scoped_lock lock(smutex); 00722 val = value; 00723 return val; 00724 } 00725 00726 atomic<T>& operator=( const atomic<T>& value ) 00727 { 00728 spin_mutex::scoped_lock lock(smutex); 00729 val = value; 00730 return *this; 00731 } 00732 00733 00734 T operator+=(T value) 00735 { 00736 spin_mutex::scoped_lock lock(smutex); 00737 val += value; 00738 return val; 00739 } 00740 00741 T operator-=(T value) 00742 { 00743 spin_mutex::scoped_lock lock(smutex); 00744 val -= value; 00745 return val; 00746 } 00747 00748 T operator++() 00749 { 00750 spin_mutex::scoped_lock lock(smutex); 00751 val++; 00752 return val; 00753 } 00754 00755 T operator++(int) 00756 { 00757 spin_mutex::scoped_lock lock(smutex); 00758 val++; 00759 return val; 00760 } 00761 00762 T operator--() 00763 { 00764 spin_mutex::scoped_lock lock(smutex); 00765 val--; 00766 return val; 00767 } 00768 00769 T operator--(int) 00770 { 00771 spin_mutex::scoped_lock lock(smutex); 00772 val--; 00773 return val; 00774 } 00775 00776 private: 00777 T val; 00778 spin_mutex smutex; 00779 }; 00780 00781 #else //LIBMESH_HAVE_PTHREAD 00782 00783 //------------------------------------------------------------------- 00787 class task_scheduler_init 00788 { 00789 public: 00790 static const int automatic = -1; 00791 explicit task_scheduler_init (int = automatic) {} 00792 void initialize (int = automatic) {} 00793 void terminate () {} 00794 }; 00795 00796 //------------------------------------------------------------------- 00801 class split {}; 00802 00803 //------------------------------------------------------------------- 00808 template <typename Range, typename Body> 00809 inline 00810 void parallel_for (const Range &range, const Body &body) 00811 { 00812 BoolAcquire b(in_threads); 00813 body(range); 00814 } 00815 00816 //------------------------------------------------------------------- 00821 template <typename Range, typename Body, typename Partitioner> 00822 inline 00823 void parallel_for (const Range &range, const Body &body, const Partitioner &) 00824 { 00825 BoolAcquire b(in_threads); 00826 body(range); 00827 } 00828 00829 //------------------------------------------------------------------- 00834 template <typename Range, typename Body> 00835 inline 00836 void parallel_reduce (const Range &range, Body &body) 00837 { 00838 BoolAcquire b(in_threads); 00839 body(range); 00840 } 00841 00842 //------------------------------------------------------------------- 00847 template <typename Range, typename Body, typename Partitioner> 00848 inline 00849 void parallel_reduce (const Range &range, Body &body, const Partitioner &) 00850 { 00851 BoolAcquire b(in_threads); 00852 body(range); 00853 } 00854 00855 //------------------------------------------------------------------- 00860 class spin_mutex 00861 { 00862 public: 00863 spin_mutex() {} 00864 void lock () {} 00865 void unlock () {} 00866 00867 class scoped_lock 00868 { 00869 public: 00870 scoped_lock () {} 00871 explicit scoped_lock ( spin_mutex& ) {} 00872 void acquire ( spin_mutex& ) {} 00873 void release () {} 00874 }; 00875 }; 00876 00877 //------------------------------------------------------------------- 00882 class recursive_mutex 00883 { 00884 public: 00885 recursive_mutex() {} 00886 00887 class scoped_lock 00888 { 00889 public: 00890 scoped_lock () {} 00891 explicit scoped_lock ( recursive_mutex& ) {} 00892 void acquire ( recursive_mutex& ) {} 00893 void release () {} 00894 }; 00895 }; 00896 00897 //------------------------------------------------------------------- 00902 template <typename T> 00903 class atomic 00904 { 00905 public: 00906 atomic () : _val(0) {} 00907 operator T& () { return _val; } 00908 private: 00909 T _val; 00910 }; 00911 00912 #endif // LIBMESH_HAVE_PTHREAD 00913 #endif // #ifdef LIBMESH_HAVE_TBB_API 00914 00915 00916 00920 template <typename T> 00921 class BlockedRange 00922 { 00923 public: 00927 typedef T const_iterator; 00928 00934 explicit BlockedRange (const unsigned int new_grainsize = 1000) : 00935 _grainsize(new_grainsize) 00936 {} 00937 00944 BlockedRange (const const_iterator first, 00945 const const_iterator last, 00946 const unsigned int new_grainsize = 1000) : 00947 _grainsize(new_grainsize) 00948 { 00949 this->reset(first, last); 00950 } 00951 00965 BlockedRange (const BlockedRange<T> &r): 00966 _end(r._end), 00967 _begin(r._begin), 00968 _grainsize(r._grainsize) 00969 {} 00970 00976 BlockedRange (BlockedRange<T> &r, Threads::split ) : 00977 _end(r._end), 00978 _begin(r._begin), 00979 _grainsize(r._grainsize) 00980 { 00981 const_iterator 00982 beginning = r._begin, 00983 ending = r._end, 00984 middle = beginning + (ending - beginning)/2u; 00985 00986 r._end = _begin = middle; 00987 } 00988 00992 void reset (const const_iterator first, 00993 const const_iterator last) 00994 { 00995 _begin = first; 00996 _end = last; 00997 } 00998 01002 const_iterator begin () const { return _begin; } 01003 01007 const_iterator end () const { return _end; } 01008 01013 unsigned int grainsize () const {return _grainsize;} 01014 01018 void grainsize (const unsigned int &gs) {_grainsize = gs;} 01019 01023 int size () const { return (_end -_begin); } 01024 01025 //------------------------------------------------------------------------ 01026 // Methods that implement Range concept 01027 //------------------------------------------------------------------------ 01028 01032 bool empty() const { return (_begin == _end); } 01033 01037 bool is_divisible() const { return ((_begin + this->grainsize()) < _end); } 01038 01039 private: 01040 01041 const_iterator _end; 01042 const_iterator _begin; 01043 unsigned int _grainsize; 01044 }; 01045 01046 01047 01051 extern spin_mutex spin_mtx; 01052 01056 extern recursive_mutex recursive_mtx; 01057 01058 } // namespace Threads 01059 01060 } // namespace libMesh 01061 01062 #endif // LIBMESH_THREADS_H