LCOV - code coverage report
Current view: top level - include/parallel - threads.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 6 6 100.0 %
Date: 2026-06-03 20:22:46 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : #ifndef LIBMESH_THREADS_H
      20             : #define LIBMESH_THREADS_H
      21             : 
      22             : // Local includes
      23             : #include "libmesh/libmesh_config.h"
      24             : #include "libmesh/libmesh_common.h"  // for libmesh_assert
      25             : 
      26             : 
      27             : // Compile-time check: TBB and pthreads are now mutually exclusive.
      28             : #if defined(LIBMESH_HAVE_TBB_API) && defined(LIBMESH_HAVE_PTHREAD)
      29             : MULTIPLE THREADING MODELS CANNOT BE SIMULTANEOUSLY ACTIVE
      30             : #endif
      31             : 
      32             : namespace libMesh
      33             : {
      34             : 
      35             : /**
      36             :  * The Threads namespace is for wrapper functions
      37             :  * for common general multithreading algorithms and tasks.
      38             :  */
      39             : namespace Threads
      40             : {
      41             : 
      42             : /**
      43             :  * An integer which is set to the number of active threads when we are
      44             :  * in a Threads:: parallel operation.
      45             :  */
      46             : extern int active_threads;
      47             : 
      48             : /**
      49             :  * A boolean which is true iff we are in a Threads:: function
      50             :  * It may be useful to assert(!Threads::in_threads), in any code which
      51             :  * is known to not be thread-safe.  Code which is not thread-safe but
      52             :  * which is specifically enabled only when multiple threads are active
      53             :  * might test for (Threads::active_threads != 1) instead.
      54             :  */
      55             : extern bool in_threads;
      56             : 
      57             : /**
      58             :  * We use a class to turn Threads::in_threads on and off, to be
      59             :  * exception-safe.
      60             :  *
      61             :  * We'll use the same class to set Threads::active_threads, for the
      62             :  * same reason, but it's a little more complicated for that.
      63             :  */
      64             : template <typename T, T new_x_default = T(), bool assert_change = false>
      65             : class RAIIAcquire
      66             : {
      67             : public:
      68             :   explicit
      69       44248 :   RAIIAcquire(T & x, T new_x = new_x_default) :
      70     6498173 :     _x(x), _old_x(x), _new_x(new_x)
      71             :   {
      72       41198 :     libmesh_assert(!assert_change || _x != _new_x);
      73     6495140 :     _x = _new_x;
      74       44248 :   }
      75             : 
      76     6492070 :   ~RAIIAcquire() { libmesh_exceptionless_assert(_x == _new_x); _x = _old_x; }
      77             : private:
      78             :   T & _x;
      79             :   T _old_x;
      80             :   T _new_x;
      81             : };
      82             : 
      83             : // We'll only acquire in_threads to turn it from false to true
      84             : typedef RAIIAcquire<bool, true, true> BoolAcquire;
      85             : 
      86             : /**
      87             :  * We use a class to turn perf logging off and on within threads, to
      88             :  * be exception-safe and to avoid forcing indirect inclusion of
      89             :  * libmesh_logging.h everywhere.
      90             :  *
      91             :  * If we have logging disabled, constructing this class should do
      92             :  * nothing; [[maybe_unused]] disables warnings about that.
      93             :  */
      94             : class [[maybe_unused]] DisablePerfLogInScope
      95             : {
      96             : public:
      97             : #ifndef LIBMESH_ENABLE_PERFORMANCE_LOGGING
      98             :   DisablePerfLogInScope() = default;
      99             :   ~DisablePerfLogInScope() = default;
     100             : #else
     101             :   DisablePerfLogInScope();
     102             :   ~DisablePerfLogInScope();
     103             : private:
     104             :   const bool _logging_was_enabled;
     105             : #endif
     106             : };
     107             : 
     108             : 
     109             : /**
     110             :  * Simple compatibility class for std::thread 'concurrent' execution.
     111             :  * Not at all concurrent, but provides a compatible interface.
     112             :  */
     113             : class NonConcurrentThread
     114             : {
     115             : public:
     116             :   /**
     117             :    * Constructor.  Takes a callable function object and executes it.
     118             :    * Our wrapper class actually blocks execution until the thread
     119             :    * is complete.
     120             :    */
     121             :   template <typename Callable>
     122             :   NonConcurrentThread (Callable f) { f(); }
     123             : 
     124             :   /**
     125             :    * Join is a no-op, since the constructor blocked until completion.
     126             :    */
     127             :   void join() {}
     128             : 
     129             :   /**
     130             :    * Always joinable.
     131             :    */
     132             :   bool joinable() const { return true; }
     133             : };
     134             : 
     135             : } // namespace Threads
     136             : 
     137             : } // namespace libMesh
     138             : 
     139             : 
     140             : 
     141             : // Include thread-model specific algorithms and objects.  These
     142             : // headers include headers of their own and handle their own
     143             : // namespacing.
     144             : #define LIBMESH_SQUASH_HEADER_WARNING
     145             : #ifdef LIBMESH_HAVE_TBB_API
     146             : # include "libmesh/threads_tbb.h"
     147             : #elif LIBMESH_HAVE_PTHREAD
     148             : # include "libmesh/threads_pthread.h"
     149             : #else
     150             : # include "libmesh/threads_none.h"
     151             : #endif
     152             : 
     153             : 
     154             : 
     155             : namespace libMesh
     156             : {
     157             : 
     158             : namespace Threads
     159             : {
     160             : 
     161             : /**
     162             :  * Blocked range which can be subdivided and executed in parallel.
     163             :  */
     164             : template <typename T>
     165             : class BlockedRange
     166             : {
     167             : public:
     168             :   /**
     169             :    * Allows an \p StoredRange to behave like an STL container.
     170             :    */
     171             :   typedef T const_iterator;
     172             : 
     173             :   /**
     174             :    * Constructor. Optionally takes the \p grainsize parameter, which is the
     175             :    * smallest chunk the range may be broken into for parallel
     176             :    * execution.
     177             :    */
     178             :   explicit BlockedRange (const unsigned int new_grainsize = libMesh::default_grainsize()) :
     179             :     _grainsize(new_grainsize)
     180             :   {}
     181             : 
     182             :   /**
     183             :    * Constructor.  Takes the beginning and end of the range.
     184             :    * Optionally takes the \p grainsize parameter, which is the
     185             :    * smallest chunk the range may be broken into for parallel
     186             :    * execution.
     187             :    */
     188             :   BlockedRange (const const_iterator first,
     189             :                 const const_iterator last,
     190             :                 const unsigned int new_grainsize = libMesh::default_grainsize()) :
     191             :     _grainsize(new_grainsize)
     192             :   {
     193             :     this->reset(first, last);
     194             :   }
     195             : 
     196             :   /**
     197             :    * Copy constructor.  The \p StoredRange can be copied into
     198             :    * subranges for parallel execution.  In this way the
     199             :    * initial \p StoredRange can be thought of as the root of
     200             :    * a binary tree.  The root element is the only element
     201             :    * which interacts with the user.  It takes a specified
     202             :    * range of objects and packs it into a contiguous vector
     203             :    * which can be split efficiently. However, there is no need
     204             :    * for the child ranges to contain this vector, so long as
     205             :    * the parent outlives the children.  So we implement
     206             :    * the copy constructor to specifically omit the \p _objs
     207             :    * vector.
     208             :    */
     209             :   BlockedRange (const BlockedRange<T> & r):
     210             :     _end(r._end),
     211             :     _begin(r._begin),
     212             :     _grainsize(r._grainsize)
     213             :   {}
     214             : 
     215             :   /**
     216             :    * Splits the range \p r.  The first half
     217             :    * of the range is left in place, the second
     218             :    * half of the range is placed in *this.
     219             :    */
     220             :   BlockedRange (BlockedRange<T> & r, Threads::split ) :
     221             :     _end(r._end),
     222             :     _begin(r._begin),
     223             :     _grainsize(r._grainsize)
     224             :   {
     225             :     const_iterator
     226             :       beginning = r._begin,
     227             :       ending    = r._end,
     228             :       middle    = beginning + (ending - beginning)/2u;
     229             : 
     230             :     r._end = _begin = middle;
     231             :   }
     232             : 
     233             :   /**
     234             :    * Resets the \p StoredRange to contain [first,last).
     235             :    */
     236             :   void reset (const const_iterator first,
     237             :               const const_iterator last)
     238             :   {
     239             :     _begin = first;
     240             :     _end   = last;
     241             :   }
     242             : 
     243             :   /**
     244             :    * Beginning of the range.
     245             :    */
     246             :   const_iterator begin () const { return _begin; }
     247             : 
     248             :   /**
     249             :    * End of the range.
     250             :    */
     251             :   const_iterator end () const { return _end; }
     252             : 
     253             :   /**
     254             :    * The grain size for the range.  The range will be subdivided into
     255             :    * subranges not to exceed the grain size.
     256             :    */
     257             :   unsigned int grainsize () const {return _grainsize;}
     258             : 
     259             :   /**
     260             :    * Set the grain size.
     261             :    */
     262             :   void grainsize (const unsigned int & gs) {_grainsize = gs;}
     263             : 
     264             :   /**
     265             :    * \returns The size of the range.
     266             :    */
     267             :   int size () const { return (_end -_begin); }
     268             : 
     269             :   //------------------------------------------------------------------------
     270             :   // Methods that implement Range concept
     271             :   //------------------------------------------------------------------------
     272             : 
     273             :   /**
     274             :    * \returns \p true if the range is empty.
     275             :    */
     276             :   bool empty() const { return (_begin == _end); }
     277             : 
     278             :   /**
     279             :    * \returns \p true if the range can be subdivided.
     280             :    */
     281             :   bool is_divisible() const { return ((_begin + this->grainsize()) < _end); }
     282             : 
     283             : private:
     284             : 
     285             :   const_iterator _end;
     286             :   const_iterator _begin;
     287             :   unsigned int _grainsize;
     288             : };
     289             : 
     290             : 
     291             : 
     292             : /**
     293             :  * A convenient spin mutex object which can be used for obtaining locks.
     294             :  */
     295             : extern spin_mutex spin_mtx;
     296             : 
     297             : /**
     298             :  * A convenient recursive mutex object which can be used for obtaining locks.
     299             :  */
     300             : extern recursive_mutex recursive_mtx;
     301             : 
     302             : } // namespace Threads
     303             : 
     304             : } // namespace libMesh
     305             : 
     306             : #endif // LIBMESH_THREADS_H

Generated by: LCOV version 1.14