$extrastylesheet
threads.h
Go to the documentation of this file.
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