58#ifndef DOXYGEN_SHOULD_SKIP_THIS
66 template <
typename FUNCTION,
typename... ARGS >
68 if (nb_threads <= 1) {
69 exec_func(0, 1, std::forward< ARGS >(func_args)...);
77 std::vector< std::thread > threads;
78 threads.reserve(nb_threads);
79 std::vector< std::exception_ptr > func_exceptions(nb_threads,
nullptr);
82 auto real_exec_func = [&exec_func, nb_threads](std::size_t this_thread,
83 std::exception_ptr& exc,
84 ARGS&... args) ->
void {
86 exec_func(this_thread, nb_threads, args...);
87 }
catch (...) { exc = std::current_exception(); }
91 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
93 std::thread(real_exec_func, i, std::ref(func_exceptions[i]), std::ref(func_args)...));
98 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
104 for (
const auto& exc: func_exceptions) {
105 if (exc !=
nullptr) { std::rethrow_exception(exc); }
111 template <
typename FUNC1,
typename FUNC2,
typename... ARGS >
115 ARGS&&... func_args) {
116 if (nb_threads <= 1) {
118 exec_func(0, 1, std::forward< ARGS >(func_args)...);
120 undo_func(0, 1, std::forward< ARGS >(func_args)...);
130 std::vector< std::thread > threads;
131 threads.reserve(nb_threads);
132 std::vector< std::exception_ptr > func_exceptions(nb_threads,
nullptr);
135 auto real_exec_func = [&exec_func, nb_threads](std::size_t this_thread,
136 std::exception_ptr& exc,
137 ARGS&... args) ->
void {
139 exec_func(this_thread, nb_threads, std::forward< ARGS >(args)...);
140 }
catch (...) { exc = std::current_exception(); }
145 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
147 std::thread(real_exec_func, i, std::ref(func_exceptions[i]), std::ref(func_args)...));
152 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
155 bool exception_raised =
false;
156 for (
const auto& exc: func_exceptions) {
157 if (exc !=
nullptr) {
158 exception_raised =
true;
164 if (exception_raised) {
167 auto real_undo_func = [&undo_func, nb_threads](std::size_t this_thread,
168 std::exception_ptr& exc,
169 ARGS&... args) ->
void {
171 undo_func(this_thread, nb_threads, args...);
172 }
catch (...) { exc = std::current_exception(); }
177 std::vector< std::exception_ptr > undo_func_exceptions(nb_threads,
nullptr);
178 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
180 if (func_exceptions[i] ==
nullptr)
181 threads.push_back(std::thread(real_undo_func,
183 std::ref(undo_func_exceptions[i]),
184 std::ref(func_args)...));
189 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
195 for (
const auto& exc: func_exceptions) {
196 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.