47 #ifdef GETFEM_HAS_OPENMP
55 #ifdef GETFEM_HAS_OPENMP
56 void parallel_execution(std::function<
void(
void)> lambda,
57 bool iterate_over_partitions);
67 std::unique_ptr<std::lock_guard<std::recursive_mutex>> plock;
68 static std::recursive_mutex mutex;
75 local_guard(std::recursive_mutex&);
78 std::recursive_mutex& mutex;
79 std::shared_ptr<std::lock_guard<std::recursive_mutex>> plock;
90 local_guard get_lock()
const;
92 mutable std::recursive_mutex mutex;
95 #define GLOBAL_OMP_GUARD getfem::omp_guard g; GMM_NOPERATION_(abs(&(g) != &(g)));
103 inline local_guard get_lock()
const {
return local_guard();}
105 #define GLOBAL_OMP_GUARD
137 struct general_tag{};
142 struct distribute_traits
144 using type = general_tag;
148 struct distribute_traits<std::vector<T>>
150 using type = vector_tag;
154 struct distribute_traits<bool>
156 using type = bool_tag;
159 template<
typename T,
typename thread_policy,
typename tag>
160 class omp_distribute_impl;
163 inline auto safe_component(V &v,
size_type i) -> decltype(v[i]){
164 GMM_ASSERT2(i < v.size(),
165 i <<
"-th partition is not available. "
166 "Probably on_thread_update "
167 "should have been called first");
171 template <
typename T,
typename thread_policy>
172 class omp_distribute_impl<T, thread_policy, general_tag> {
174 std::vector<T> thread_values;
175 friend struct all_values_proxy;
177 struct all_values_proxy{
178 omp_distribute_impl& distro;
179 all_values_proxy(omp_distribute_impl& d)
183 void operator = (
const T& x){
184 for(
auto it = distro.thread_values.begin();
185 it != distro.thread_values.end(); ++it){
193 template <
class... args>
194 explicit omp_distribute_impl(args&&... value){
195 thread_values.reserve(num_threads());
196 for (
size_type i = 0; i != num_threads(); ++i){
197 thread_values.emplace_back(std::forward<args>(value)...);
202 return operator()(this_thread());
205 operator const T& ()
const {
206 return operator()(this_thread());
210 return operator()(this_thread());
213 const T& thrd_cast()
const {
214 return operator()(this_thread());
218 return safe_component(thread_values, i);
222 return safe_component(thread_values, i);
225 void on_thread_update() {
226 if (thread_values.size() == num_threads())
return;
228 if (thread_values.size() != num_threads()) {
229 thread_values.resize(num_threads());
234 return thread_policy::num_threads();
238 return thread_policy::this_thread();
241 T& operator = (
const T& x){
245 else all_threads() = x;
250 all_values_proxy all_threads(){
251 return all_values_proxy(*
this);
256 template <
typename T,
257 typename thread_policy>
258 class omp_distribute_impl<std::vector<T>, thread_policy, vector_tag>
259 :
public omp_distribute_impl<std::vector<T>, thread_policy, general_tag>
262 using base = omp_distribute_impl<std::vector<T>, thread_policy, general_tag>;
264 template <
class... args>
265 explicit omp_distribute_impl(args&&... value)
266 : base(std::forward<args>(value)...)
270 return base::thrd_cast()[i];
273 return base::thrd_cast()[i];
276 std::vector<T>& operator = (
const std::vector<T>& x){
277 return base::operator=(x);
284 template <
typename thread_policy>
285 class omp_distribute_impl<bool, thread_policy, bool_tag>
286 :
public omp_distribute_impl<int, thread_policy, general_tag>
289 using base = omp_distribute_impl<int, thread_policy, general_tag>;
291 template <
class... Args>
292 explicit omp_distribute_impl(Args&&... value)
293 : base(std::forward<Args>(value)...)
296 operator bool ()
const {
297 return base::operator
const int&();
300 bool operator = (
const bool& x){
301 return base::operator=(x);
307 template<
typename T,
typename thread_policy>
308 using od_base =
typename detail::omp_distribute_impl
309 <T, thread_policy,
typename detail::distribute_traits<T>::type>;
327 using base = od_base<T, thread_policy>;
329 template <
class... args>
331 : base(std::forward<args>(value)...)
334 auto operator = (
const T& x) -> decltype(std::declval<base>() = x){
335 return base::operator=(x);
343 #ifdef GETFEM_HAS_OPENMP
344 #define THREAD_SAFE_STATIC thread_local
346 #define THREAD_SAFE_STATIC static
369 std::set<size_type>::const_iterator it);
372 std::set<size_type>::const_iterator it;
375 enum class thread_behaviour {true_threads, partition_threads};
410 void check_threads();
414 void rewind_partitions();
417 friend void parallel_execution(std::function<
void(
void)> lambda,
bool iterate_over_partitions);
426 void update_partitions();
430 std::atomic<size_type> nb_user_threads;
431 thread_behaviour behaviour = thread_behaviour::partition_threads;
432 std::atomic<bool> partitions_updated{
false};
434 bool partitions_set_by_user =
false;
445 std::unique_ptr<standard_locale> plocale;
446 std::unique_ptr<thread_exception> pexception;
450 void run_lambda(std::function<
void(
void)> lambda);
455 #define pragma_op(arg) _Pragma("arg")
457 #define pragma_op(arg) __pragma(arg)
466 #ifdef GETFEM_HAS_OPENMP
467 #define GETFEM_OMP_PARALLEL(body) getfem::parallel_execution([&](){body;}, true);
470 #define GETFEM_OMP_PARALLEL_NO_PARTITION(body) getfem::parallel_execution([&](){body;}, false);
473 #define GETFEM_OMP_FOR(init, check, increment, body) {\
474 auto boilerplate = getfem::parallel_boilerplate{}; \
475 pragma_op(omp parallel for) \
476 for (init; check; increment){ \
477 boilerplate.run_lambda([&](){body;}); \
482 #define GETFEM_OMP_PARALLEL(body) body
483 #define GETFEM_OMP_PARALLEL_NO_PARTITION(body) body;
484 #define GETFEM_OMP_FOR(init, check, increment, body)\
485 for (init; check; increment) { \
defines and typedefs for namespace bgeot
Use this template class for any object you want to distribute to open_MP threads.
Encapsulates open_mp-related initialization and de-initialization.
Iterator that runs over partitions on the current thread and sets the global (but thread-specific) pa...
A singleton that Manages partitions on individual threads.
partition_iterator begin()
beginning of the partitions for the current thread
size_type get_current_partition() const
active partition on the thread.
size_type get_nb_partitions() const
number of partitions or threads, depending on thread policy
partition_iterator end()
end of the partitions for the current thread
void set_nb_partitions(size_type)
for thread_behaviour::partition_threads set the total number of partitions.
void set_behaviour(thread_behaviour)
Sets the behaviour for the full program: either partitioning parallel loops according to the number o...
Identical to gmm::standard_locale, but does not change std::locale in multi-threaded sections of the ...
Allows to re-throw exceptions, generated in OpemMP parallel section.
size_t size_type
used as the common size type in the library
GEneric Tool for Finite Element Methods.
bool not_multithreaded()
is the program is running on a single thread
size_type max_concurrency()
Maximum number of threads that can run concurrently.
bool me_is_multithreaded_now()
is the program running in the parallel section
void set_num_threads(int n)
set maximum number of OpenMP threads
Thread policy, regulated by partition_master (can be true thread- or partition-based)
Thread policy, where partitioning is based on true threads.