Line data Source code
1 : // The libMesh Finite Element Library. 2 : // Copyright (C) 2002-2025 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 : * A boolean which is true iff we are in a Threads:: function 44 : * It may be useful to assert(!Threads::in_threads) in any code 45 : * which is known to not be thread-safe. 46 : */ 47 : extern bool in_threads; 48 : 49 : /** 50 : * We use a class to turn Threads::in_threads on and off, to be 51 : * exception-safe. 52 : */ 53 : class BoolAcquire 54 : { 55 : public: 56 : explicit 57 4245695 : BoolAcquire(bool & b) : _b(b) { libmesh_assert(!_b); _b = true; } 58 : 59 4245695 : ~BoolAcquire() { libmesh_exceptionless_assert(_b); _b = false; } 60 : private: 61 : bool & _b; 62 : }; 63 : 64 : /** 65 : * We use a class to turn perf logging off and on within threads, to 66 : * be exception-safe and to avoid forcing indirect inclusion of 67 : * libmesh_logging.h everywhere. 68 : * 69 : * If we have logging disabled, constructing this class should do 70 : * nothing; [[maybe_unused]] disables warnings about that. 71 : */ 72 : class [[maybe_unused]] DisablePerfLogInScope 73 : { 74 : public: 75 : #ifndef LIBMESH_ENABLE_PERFORMANCE_LOGGING 76 : DisablePerfLogInScope() = default; 77 : ~DisablePerfLogInScope() = default; 78 : #else 79 : DisablePerfLogInScope(); 80 : ~DisablePerfLogInScope(); 81 : private: 82 : const bool _logging_was_enabled; 83 : #endif 84 : }; 85 : 86 : 87 : /** 88 : * Simple compatibility class for std::thread 'concurrent' execution. 89 : * Not at all concurrent, but provides a compatible interface. 90 : */ 91 : class NonConcurrentThread 92 : { 93 : public: 94 : /** 95 : * Constructor. Takes a callable function object and executes it. 96 : * Our wrapper class actually blocks execution until the thread 97 : * is complete. 98 : */ 99 : template <typename Callable> 100 : NonConcurrentThread (Callable f) { f(); } 101 : 102 : /** 103 : * Join is a no-op, since the constructor blocked until completion. 104 : */ 105 : void join() {} 106 : 107 : /** 108 : * Always joinable. 109 : */ 110 : bool joinable() const { return true; } 111 : }; 112 : 113 : } // namespace Threads 114 : 115 : } // namespace libMesh 116 : 117 : 118 : 119 : // Include thread-model specific algorithms and objects. These 120 : // headers include headers of their own and handle their own 121 : // namespacing. 122 : #define LIBMESH_SQUASH_HEADER_WARNING 123 : #ifdef LIBMESH_HAVE_TBB_API 124 : # include "libmesh/threads_tbb.h" 125 : #elif LIBMESH_HAVE_PTHREAD 126 : # include "libmesh/threads_pthread.h" 127 : #else 128 : # include "libmesh/threads_none.h" 129 : #endif 130 : 131 : 132 : 133 : namespace libMesh 134 : { 135 : 136 : namespace Threads 137 : { 138 : 139 : /** 140 : * Blocked range which can be subdivided and executed in parallel. 141 : */ 142 : template <typename T> 143 : class BlockedRange 144 : { 145 : public: 146 : /** 147 : * Allows an \p StoredRange to behave like an STL container. 148 : */ 149 : typedef T const_iterator; 150 : 151 : /** 152 : * Constructor. Optionally takes the \p grainsize parameter, which is the 153 : * smallest chunk the range may be broken into for parallel 154 : * execution. 155 : */ 156 : explicit BlockedRange (const unsigned int new_grainsize = 1000) : 157 : _grainsize(new_grainsize) 158 : {} 159 : 160 : /** 161 : * Constructor. Takes the beginning and end of the range. 162 : * Optionally takes the \p grainsize parameter, which is the 163 : * smallest chunk the range may be broken into for parallel 164 : * execution. 165 : */ 166 : BlockedRange (const const_iterator first, 167 : const const_iterator last, 168 : const unsigned int new_grainsize = 1000) : 169 : _grainsize(new_grainsize) 170 : { 171 : this->reset(first, last); 172 : } 173 : 174 : /** 175 : * Copy constructor. The \p StoredRange can be copied into 176 : * subranges for parallel execution. In this way the 177 : * initial \p StoredRange can be thought of as the root of 178 : * a binary tree. The root element is the only element 179 : * which interacts with the user. It takes a specified 180 : * range of objects and packs it into a contiguous vector 181 : * which can be split efficiently. However, there is no need 182 : * for the child ranges to contain this vector, so long as 183 : * the parent outlives the children. So we implement 184 : * the copy constructor to specifically omit the \p _objs 185 : * vector. 186 : */ 187 : BlockedRange (const BlockedRange<T> & r): 188 : _end(r._end), 189 : _begin(r._begin), 190 : _grainsize(r._grainsize) 191 : {} 192 : 193 : /** 194 : * Splits the range \p r. The first half 195 : * of the range is left in place, the second 196 : * half of the range is placed in *this. 197 : */ 198 : BlockedRange (BlockedRange<T> & r, Threads::split ) : 199 : _end(r._end), 200 : _begin(r._begin), 201 : _grainsize(r._grainsize) 202 : { 203 : const_iterator 204 : beginning = r._begin, 205 : ending = r._end, 206 : middle = beginning + (ending - beginning)/2u; 207 : 208 : r._end = _begin = middle; 209 : } 210 : 211 : /** 212 : * Resets the \p StoredRange to contain [first,last). 213 : */ 214 : void reset (const const_iterator first, 215 : const const_iterator last) 216 : { 217 : _begin = first; 218 : _end = last; 219 : } 220 : 221 : /** 222 : * Beginning of the range. 223 : */ 224 : const_iterator begin () const { return _begin; } 225 : 226 : /** 227 : * End of the range. 228 : */ 229 : const_iterator end () const { return _end; } 230 : 231 : /** 232 : * The grain size for the range. The range will be subdivided into 233 : * subranges not to exceed the grain size. 234 : */ 235 : unsigned int grainsize () const {return _grainsize;} 236 : 237 : /** 238 : * Set the grain size. 239 : */ 240 : void grainsize (const unsigned int & gs) {_grainsize = gs;} 241 : 242 : /** 243 : * \returns The size of the range. 244 : */ 245 : int size () const { return (_end -_begin); } 246 : 247 : //------------------------------------------------------------------------ 248 : // Methods that implement Range concept 249 : //------------------------------------------------------------------------ 250 : 251 : /** 252 : * \returns \p true if the range is empty. 253 : */ 254 : bool empty() const { return (_begin == _end); } 255 : 256 : /** 257 : * \returns \p true if the range can be subdivided. 258 : */ 259 : bool is_divisible() const { return ((_begin + this->grainsize()) < _end); } 260 : 261 : private: 262 : 263 : const_iterator _end; 264 : const_iterator _begin; 265 : unsigned int _grainsize; 266 : }; 267 : 268 : 269 : 270 : /** 271 : * A convenient spin mutex object which can be used for obtaining locks. 272 : */ 273 : extern spin_mutex spin_mtx; 274 : 275 : /** 276 : * A convenient recursive mutex object which can be used for obtaining locks. 277 : */ 278 : extern recursive_mutex recursive_mtx; 279 : 280 : } // namespace Threads 281 : 282 : } // namespace libMesh 283 : 284 : #endif // LIBMESH_THREADS_H