diff options
author | Remco Burema <r.burema@ultimaker.com> | 2021-11-03 18:56:39 +0300 |
---|---|---|
committer | Remco Burema <r.burema@ultimaker.com> | 2021-11-03 20:30:40 +0300 |
commit | 7f1cba66105103a26b6c2d1ca98c3ea86e0d431c (patch) | |
tree | b6dbea180f6ff873a7a5240d412a5b38e9f21989 /src | |
parent | 9042a0a4e2f31aef5c96d789c01b2ac10d676140 (diff) |
'Manual' parallel for loop.
Since not all compilers implement the full C++17 yet, specifically the Parallel Execution TS wasn't added to their respective libraries yet.
done as part of CURA-8573
Diffstat (limited to 'src')
-rw-r--r-- | src/utils/algorithm.h | 54 |
1 files changed, 52 insertions, 2 deletions
diff --git a/src/utils/algorithm.h b/src/utils/algorithm.h index 3cc2fe2d8..adb130ef3 100644 --- a/src/utils/algorithm.h +++ b/src/utils/algorithm.h @@ -1,11 +1,13 @@ -/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */ +/** Copyright (C) 2021 Ultimaker - Released under terms of the AGPLv3 License */ #ifndef UTILS_ALGORITHM_H #define UTILS_ALGORITHM_H #include <algorithm> -#include <vector> +#include <atomic> #include <functional> +#include <future> #include <numeric> +#include <vector> // extensions to algorithm.h from the standard library @@ -41,6 +43,54 @@ std::vector<size_t> order(const std::vector<T> &in) return order; } +/* An implementation of parallel for. + * There are still a lot of compilers that claim to be fully C++17 compatible, but don't implement the Parallel Execution TS of the accompanying standard lybrary. + * This means that we moslty have to fall back to the things that C++11/14 provide when it comes to threading/parallelism/etc. + * + * \param from The index starts here (inclusive). + * \param to The index ends here (not inclusive). + * \param increment Add this to the index each time. + * \param body The loop-body, as a closure. Receives the index on invocation. + */ +template<typename T> +void parallel_for(T from, T to, T increment, const std::function<void(const T)>& body) +{ + // Sanity tests. + assert(increment > 0); + assert(from <= to); + + // Set the values so that 'to' is a whole integer multiple apart from 'from' (& early out if needed). + to = from + increment * (((to - from) + (increment - static_cast<T>(1))) / increment); + if (to == from) + { + return; + } + + // Set an atomic countdown variable to how many tasks need to be completed. + std::atomic<T> tasks_pending((to - from) / increment); + + // Wrap the loop-body, so that the outer scope can be notified by 'all_tasks_done'. + std::promise<void> all_tasks_done; + const auto func = + [&body, &tasks_pending, &all_tasks_done](const T index) + { + body(index); + if (--tasks_pending == 0) + { + all_tasks_done.set_value(); + } + }; + + // Run all tasks. + for (size_t index = from; index != to; index += increment) + { + std::async(std::launch::async, func, index); + } + + // Wait for the end-result before return. + all_tasks_done.get_future().wait(); +} + } // namespace cura #endif // UTILS_ALGORITHM_H |