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
|