48 #ifdef GETFEM_HAS_OPENMP
56 #ifdef GETFEM_HAS_OPENMP
57 void parallel_execution(std::function<
void(
void)> lambda,
58 bool iterate_over_partitions);
68 std::unique_ptr<std::lock_guard<std::recursive_mutex>> plock;
69 static std::recursive_mutex mutex;
76 local_guard(std::recursive_mutex&);
79 std::recursive_mutex& mutex;
80 std::shared_ptr<std::lock_guard<std::recursive_mutex>> plock;
91 local_guard get_lock()
const;
93 mutable std::recursive_mutex mutex;
96 #define GLOBAL_OMP_GUARD getfem::omp_guard g; GMM_NOPERATION_(abs(&(g) != &(g)));
104 inline local_guard get_lock()
const {
return local_guard();}
106 #define GLOBAL_OMP_GUARD
138 struct general_tag{};
143 struct distribute_traits
145 using type = general_tag;
149 struct distribute_traits<std::vector<T>>
151 using type = vector_tag;
155 struct distribute_traits<bool>
157 using type = bool_tag;
160 template<
typename T,
typename thread_policy,
typename tag>
161 class omp_distribute_impl;
164 inline auto safe_component(V &v,
size_type i) -> decltype(v[i]){
165 GMM_ASSERT2(i < v.size(),
166 i <<
"-th partition is not available. "
167 "Probably on_thread_update "
168 "should have been called first");
172 template <
typename T,
typename thread_policy>
173 class omp_distribute_impl<T, thread_policy, general_tag> {
175 std::vector<T> thread_values;
176 friend struct all_values_proxy;
178 struct all_values_proxy{
179 omp_distribute_impl& distro;
180 all_values_proxy(omp_distribute_impl& d)
184 void operator = (
const T& x){
185 for(
auto it = distro.thread_values.begin();
186 it != distro.thread_values.end(); ++it){
194 template <
class... args>
195 explicit omp_distribute_impl(args&&... value){
196 thread_values.reserve(num_threads());
197 for (
size_type i = 0; i != num_threads(); ++i){
198 thread_values.emplace_back(std::forward<args>(value)...);
203 return operator()(this_thread());
206 operator const T& ()
const {
207 return operator()(this_thread());
211 return operator()(this_thread());
214 const T& thrd_cast()
const {
215 return operator()(this_thread());
219 return safe_component(thread_values, i);
223 return safe_component(thread_values, i);
226 void on_thread_update() {
227 if (thread_values.size() == num_threads())
return;
229 if (thread_values.size() != num_threads()) {
230 thread_values.resize(num_threads());
235 return thread_policy::num_threads();
239 return thread_policy::this_thread();
242 T& operator = (
const T& x){
246 else all_threads() = x;
251 all_values_proxy all_threads(){
252 return all_values_proxy(*
this);
257 template <
typename T,
258 typename thread_policy>
259 class omp_distribute_impl<std::vector<T>, thread_policy, vector_tag>
260 :
public omp_distribute_impl<std::vector<T>, thread_policy, general_tag>
263 using base = omp_distribute_impl<std::vector<T>, thread_policy, general_tag>;
265 template <
class... args>
266 explicit omp_distribute_impl(args&&... value)
267 : base(std::forward<args>(value)...)
271 return base::thrd_cast()[i];
274 return base::thrd_cast()[i];
277 std::vector<T>& operator = (
const std::vector<T>& x){
278 return base::operator=(x);
285 template <
typename thread_policy>
286 class omp_distribute_impl<bool, thread_policy, bool_tag>
287 :
public omp_distribute_impl<int, thread_policy, general_tag>
290 using base = omp_distribute_impl<int, thread_policy, general_tag>;
292 template <
class... Args>
293 explicit omp_distribute_impl(Args&&... value)
294 : base(std::forward<Args>(value)...)
297 operator bool ()
const {
298 return base::operator
const int&();
301 bool operator = (
const bool& x){
302 return base::operator=(x);
308 template<
typename T,
typename thread_policy>
309 using od_base =
typename detail::omp_distribute_impl
310 <T, thread_policy,
typename detail::distribute_traits<T>::type>;
328 using base = od_base<T, thread_policy>;
330 template <
class... args>
332 : base(std::forward<args>(value)...)
335 auto operator = (
const T& x) -> decltype(std::declval<base>() = x){
336 return base::operator=(x);
344 #ifdef GETFEM_HAS_OPENMP
345 #define THREAD_SAFE_STATIC thread_local
347 #define THREAD_SAFE_STATIC static
370 std::set<size_type>::const_iterator it);
373 std::set<size_type>::const_iterator it;
376 enum class thread_behaviour {true_threads, partition_threads};
411 void check_threads();
415 void rewind_partitions();
418 friend void parallel_execution(std::function<
void(
void)> lambda,
bool iterate_over_partitions);
427 void update_partitions();
431 std::atomic<size_type> nb_user_threads;
432 thread_behaviour behaviour = thread_behaviour::partition_threads;
433 std::atomic<bool> partitions_updated{
false};
435 bool partitions_set_by_user =
false;
446 std::unique_ptr<standard_locale> plocale;
447 std::unique_ptr<thread_exception> pexception;
451 void run_lambda(std::function<
void(
void)> lambda);
456 #define pragma_op(arg) _Pragma("arg")
458 #define pragma_op(arg) __pragma(arg)
467 #ifdef GETFEM_HAS_OPENMP
468 #define GETFEM_OMP_PARALLEL(body) getfem::parallel_execution([&](){body;}, true);
471 #define GETFEM_OMP_PARALLEL_NO_PARTITION(body) getfem::parallel_execution([&](){body;}, false);
474 #define GETFEM_OMP_FOR(init, check, increment, body) {\
475 auto boilerplate = getfem::parallel_boilerplate{}; \
476 pragma_op(omp parallel for) \
477 for (init; check; increment){ \
478 boilerplate.run_lambda([&](){body;}); \
483 #define GETFEM_OMP_PARALLEL(body) body
484 #define GETFEM_OMP_PARALLEL_NO_PARTITION(body) body;
485 #define GETFEM_OMP_FOR(init, check, increment, body)\
486 for (init; check; increment) { \