subpar
Substitutable parallelization for C++ libraries
Loading...
Searching...
No Matches
simple.hpp
Go to the documentation of this file.
1#ifndef SUBPAR_SIMPLE_HPP
2#define SUBPAR_SIMPLE_HPP
3
4#include "range.hpp"
5
6#ifndef SUBPAR_CUSTOM_PARALLELIZE_SIMPLE
7#include <vector>
8#include <stdexcept>
9#include <thread>
10#include <type_traits>
11#endif
12
18namespace subpar {
19
52template<bool nothrow_ = false, typename Task_, class Run_>
53void parallelize_simple(const Task_ num_tasks, const Run_ run_task) {
54#ifdef SUBPAR_CUSTOM_PARALLELIZE_SIMPLE
55 if constexpr(nothrow_) {
56#ifdef SUBPAR_CUSTOM_PARALLELIZE_SIMPLE_NOTHROW
57 SUBPAR_CUSTOM_PARALLELIZE_SIMPLE_NOTHROW(num_tasks, run_task);
58#else
59 SUBPAR_CUSTOM_PARALLELIZE_SIMPLE(num_tasks, run_task);
60#endif
61 } else {
62 SUBPAR_CUSTOM_PARALLELIZE_SIMPLE(num_tasks, run_task);
63 }
64
65#else
66 if (num_tasks == 0) {
67 return;
68 } else if (num_tasks == 1) {
69 run_task(0);
70 return;
71 }
72
73 // Avoid instantiating a vector if it is known that the function can't throw.
74 auto errors = [&]{
75 if constexpr(nothrow_) {
76 return true;
77 } else {
78 return sanisizer::create<std::vector<std::exception_ptr> >(num_tasks);
79 }
80 }();
81
82#if defined(_OPENMP) && !defined(SUBPAR_NO_OPENMP_SIMPLE)
83#define SUBPAR_USES_OPENMP_SIMPLE 1
84
85 // OpenMP doesn't guarantee that we'll actually start 'num_tasks' workers,
86 // so we need to do a loop here to ensure that each task simple is executed.
87 #pragma omp parallel for num_threads(num_tasks)
88 for (Task_ w = 0; w < num_tasks; ++w) {
89 if constexpr(nothrow_) {
90 run_task(w);
91 } else {
92 try {
93 run_task(w);
94 } catch (...) {
95 errors[w] = std::current_exception();
96 }
97 }
98 }
99
100#else
101// Wiping it out, just in case.
102#undef SUBPAR_USES_OPENMP_SIMPLE
103
104 std::vector<std::thread> workers;
105 workers.reserve(sanisizer::cast<decltype(workers.size())>(num_tasks)); // make sure we don't get alloc errors during emplace_back().
106
107 for (Task_ w = 0; w < num_tasks; ++w) {
108 if constexpr(nothrow_) {
109 workers.emplace_back(run_task, w);
110 } else {
111 workers.emplace_back([&run_task,&errors](int w) -> void {
112 try {
113 run_task(w);
114 } catch (...) {
115 errors[w] = std::current_exception();
116 }
117 }, w);
118 }
119 }
120
121 for (auto& wrk : workers) {
122 wrk.join();
123 }
124#endif
125
126 if constexpr(!nothrow_) {
127 for (const auto& e : errors) {
128 if (e) {
129 std::rethrow_exception(e);
130 }
131 }
132 }
133#endif
134}
135
136}
137
138#endif
Substitutable parallelization functions.
void parallelize_simple(const Task_ num_tasks, const Run_ run_task)
Parallelize individual tasks across workers.
Definition simple.hpp:53
Parallelize across a range of tasks.