57#ifndef DOXYGEN_SHOULD_SKIP_THIS
65 template <
typename FUNCTION,
typename... ARGS >
67 if (nb_threads <= 1) {
68 exec_func(0, 1, std::forward< ARGS >(func_args)...);
76 std::vector< std::thread > threads;
77 threads.reserve(nb_threads);
78 std::vector< std::exception_ptr > func_exceptions(nb_threads,
nullptr);
81 auto real_exec_func = [&exec_func, nb_threads](std::size_t this_thread,
82 std::exception_ptr& exc,
83 ARGS&... args) ->
void {
85 exec_func(this_thread, nb_threads, std::forward< ARGS >(args)...);
86 }
catch (...) { exc = std::current_exception(); }
90 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
92 std::thread(real_exec_func, i, std::ref(func_exceptions[i]), std::ref(func_args)...));
97 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
103 for (
const auto& exc: func_exceptions) {
104 if (exc !=
nullptr) { std::rethrow_exception(exc); }
110 template <
typename FUNC1,
typename FUNC2,
typename... ARGS >
114 ARGS&&... func_args) {
115 if (nb_threads <= 1) {
117 exec_func(0, 1, std::forward< ARGS >(func_args)...);
119 undo_func(0, 1, std::forward< ARGS >(func_args)...);
129 std::vector< std::thread > threads;
130 threads.reserve(nb_threads);
131 std::vector< std::exception_ptr > func_exceptions(nb_threads,
nullptr);
134 auto real_exec_func = [&exec_func, nb_threads](std::size_t this_thread,
135 std::exception_ptr& exc,
136 ARGS&... args) ->
void {
138 exec_func(this_thread, nb_threads, std::forward< ARGS >(args)...);
139 }
catch (...) { exc = std::current_exception(); }
144 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
146 std::thread(real_exec_func, i, std::ref(func_exceptions[i]), std::ref(func_args)...));
151 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
154 bool exception_raised =
false;
155 for (
const auto& exc: func_exceptions) {
156 if (exc !=
nullptr) {
157 exception_raised =
true;
163 if (exception_raised) {
166 auto real_undo_func = [&undo_func, nb_threads](std::size_t this_thread,
167 std::exception_ptr& exc,
168 ARGS&... args) ->
void {
170 undo_func(this_thread, nb_threads, std::forward< ARGS >(args)...);
171 }
catch (...) { exc = std::current_exception(); }
176 std::vector< std::exception_ptr > undo_func_exceptions(nb_threads,
nullptr);
177 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
179 if (func_exceptions[i] ==
nullptr)
180 threads.push_back(std::thread(real_undo_func,
182 std::ref(undo_func_exceptions[i]),
183 std::ref(func_args)...));
188 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
194 for (
const auto& exc: func_exceptions) {
195 if (exc !=
nullptr) { std::rethrow_exception(exc); }
static std::atomic< int > nbRunningThreadsExecutors_
he number of currently running ThreadExecutors
gum is the global namespace for all aGrUM entities
static void execute(std::size_t nb_threads, FUNCTION exec_func, ARGS &&... func_args)
executes a function using several threads
static void executeOrUndo(std::size_t nb_threads, FUNC1 exec_func, FUNC2 undo_func, ARGS &&... func_args)
executes in parallel a function and undoes it if execptions are raised
A class to execute several threads by exploiting std::thread.