22 #ifndef TLP_PARALLEL_TOOLS_H
23 #define TLP_PARALLEL_TOOLS_H
25 #include <tulip/tulipconf.h>
28 #ifndef TLP_NO_THREADS
36 typedef long long OMP_ITER_TYPE;
38 typedef size_t OMP_ITER_TYPE;
41 #define OMP(x) _Pragma(STRINGIFY(omp x))
42 #define OMP_CRITICAL_SECTION(x) _Pragma(STRINGIFY(omp critical(x)))
44 #define OMP(x) __pragma(omp x)
45 #define OMP_CRITICAL_SECTION(x) __pragma(omp critical(x))
74 class TLP_SCOPE ThreadManager {
76 static unsigned int maxNumberOfThreads;
78 #if !defined(TLP_NO_THREADS) && !defined(_OPENMP)
81 static void allocateThreadNumber();
84 static void freeThreadNumber();
88 template <
typename runFunction>
89 static inline std::thread *launchThread(
const runFunction &f, uint begin, uint end) {
90 auto thrdFunction = [&](uint begin, uint end) {
91 allocateThreadNumber();
95 return new std::thread(thrdFunction, begin, end);
101 #if !defined(TLP_NO_THREADS) && !defined(_OPENMP)
105 template <
typename runFunction>
106 static inline std::thread *launchThread(
const runFunction &f) {
107 auto thrdFunction = [&]() {
108 allocateThreadNumber();
112 return new std::thread(thrdFunction);
120 static unsigned int getNumberOfProcs();
125 static unsigned int getNumberOfThreads();
130 static void setNumberOfThreads(
unsigned int nbThreads);
135 static unsigned int getThreadNumber();
143 template <
typename ThreadFunction>
144 static inline void iterate(
size_t maxId,
const ThreadFunction &threadFunction) {
145 #ifndef TLP_NO_THREADS
150 size_t nbPerThread = maxId == 1 ? 1 : std::max(maxId / (maxNumberOfThreads - 1),
size_t(2));
152 size_t begin = 0, end = nbPerThread;
153 maxId -= end - begin;
155 std::vector<std::thread *> threads;
156 threads.reserve(maxNumberOfThreads - 1);
158 threads.push_back(launchThread(threadFunction, begin, end));
159 if (nbPerThread > 1) {
160 if (maxNumberOfThreads - threads.size() == maxId)
164 end += std::min(nbPerThread, maxId);
165 maxId -= end - begin;
168 threadFunction(begin, end);
170 for (
auto thrd : threads) {
175 threadFunction(0, maxId);
182 #ifndef TLP_NO_THREADS
184 #define TLP_MAX_NB_THREADS 128
186 #define TLP_NB_THREADS tlp::ThreadManager::getNumberOfThreads()
208 #define TLP_LOCK_SECTION(mtx) \
209 static tlp::OpenMPLock mtx; \
211 #define TLP_UNLOCK_SECTION(mtx) mtx.unlock();
212 #define TLP_DECLARE_GLOBAL_LOCK(mtx) extern tlp::OpenMPLock mtx
213 #define TLP_DEFINE_GLOBAL_LOCK(mtx) tlp::OpenMPLock mtx
214 #define TLP_GLOBALLY_LOCK_SECTION(mtx) mtx.lock();
215 #define TLP_GLOBALLY_UNLOCK_SECTION(mtx) mtx.unlock()
219 #define TLP_LOCK_SECTION(mtx) OMP_CRITICAL_SECTION(mtx)
220 #define TLP_UNLOCK_SECTION(mtx)
221 #define TLP_DECLARE_GLOBAL_LOCK(mtx) extern void mtx()
222 #define TLP_DEFINE_GLOBAL_LOCK(mtx) extern void mtx()
223 #define TLP_GLOBALLY_LOCK_SECTION(mtx) OMP_CRITICAL_SECTION(mtx)
224 #define TLP_GLOBALLY_UNLOCK_SECTION(mtx)
230 #define TLP_LOCK_SECTION(mtx) \
231 static std::mutex mtx; \
233 #define TLP_UNLOCK_SECTION(mtx) mtx.unlock()
234 #define TLP_DECLARE_GLOBAL_LOCK(mtx) extern std::mutex mtx
235 #define TLP_DEFINE_GLOBAL_LOCK(mtx) std::mutex mtx
236 #define TLP_GLOBALLY_LOCK_SECTION(mtx) mtx.lock();
237 #define TLP_GLOBALLY_UNLOCK_SECTION(mtx) mtx.unlock()
244 #define TLP_MAX_NB_THREADS 1
246 #define TLP_NB_THREADS 1
248 #define TLP_LOCK_SECTION(mtx)
249 #define TLP_UNLOCK_SECTION(mtx)
250 #define TLP_DECLARE_GLOBAL_LOCK(mtx) extern void mtx()
251 #define TLP_DEFINE_GLOBAL_LOCK(mtx) extern void mtx()
252 #define TLP_GLOBALLY_LOCK_SECTION(mtx)
253 #define TLP_GLOBALLY_UNLOCK_SECTION(mtx)
284 template <
typename IdxFunction>
285 void inline TLP_PARALLEL_MAP_INDICES(
size_t maxIdx,
const IdxFunction &idxFunction) {
288 for (OMP_ITER_TYPE i = 0; i < OMP_ITER_TYPE(maxIdx); ++i) {
292 auto threadFunction = [&](
size_t begin,
size_t end) {
293 for (; begin < end; ++begin) {
297 ThreadManager::iterate(maxIdx, threadFunction);
301 template <
typename EltType,
typename IdxFunction>
302 void inline TLP_PARALLEL_MAP_VECTOR(
const std::vector<EltType> &vect,
303 const IdxFunction &idxFunction) {
305 auto maxIdx = vect.size();
307 for (OMP_ITER_TYPE i = 0; i < OMP_ITER_TYPE(maxIdx); ++i) {
308 idxFunction(vect[i]);
311 auto threadFunction = [&](
size_t begin,
size_t end) {
312 for (; begin < end; ++begin) {
313 idxFunction(vect[begin]);
317 ThreadManager::iterate(vect.size(), threadFunction);
321 template <
typename EltType,
typename IdxFunction>
322 void inline TLP_PARALLEL_MAP_VECTOR_AND_INDICES(
const std::vector<EltType> &vect,
323 const IdxFunction &idxFunction) {
325 auto maxIdx = vect.size();
327 for (OMP_ITER_TYPE i = 0; i < OMP_ITER_TYPE(maxIdx); ++i) {
328 idxFunction(vect[i], i);
331 auto threadFunction = [&](
size_t begin,
size_t end) {
332 for (; begin < end; ++begin) {
333 idxFunction(vect[begin], begin);
337 ThreadManager::iterate(vect.size(), threadFunction);
341 template <
typename F1,
typename F2>
342 void inline TLP_PARALLEL_SECTIONS(
const F1 &f1,
const F2 &f2) {
343 #ifndef TLP_NO_THREADS
346 OMP(sections nowait) {
356 auto thrd = ThreadManager::launchThread(f1);
367 template <
typename F1,
typename F2,
typename F3>
368 void inline TLP_PARALLEL_SECTIONS(
const F1 &f1,
const F2 &f2,
const F3 &f3) {
369 #ifndef TLP_NO_THREADS
372 OMP(sections nowait) {
385 auto thrd1 = ThreadManager::launchThread(f1);
386 auto thrd2 = ThreadManager::launchThread(f2);
400 template <
typename F1,
typename F2,
typename F3,
typename F4>
401 void inline TLP_PARALLEL_SECTIONS(
const F1 &f1,
const F2 &f2,
const F3 &f3,
const F4 &f4) {
402 #ifndef TLP_NO_THREADS
405 OMP(sections nowait) {
421 auto thrd1 = ThreadManager::launchThread(f1);
422 auto thrd2 = ThreadManager::launchThread(f2);
423 auto thrd3 = ThreadManager::launchThread(f3);