22#ifndef TLP_PARALLEL_TOOLS_H
23#define TLP_PARALLEL_TOOLS_H
25#include <tulip/tulipconf.h>
36typedef long long OMP_ITER_TYPE;
38typedef 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))
74class 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)
284template <
typename IdxFunction>
285void 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);
301template <
typename EltType,
typename IdxFunction>
302void 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);
321template <
typename EltType,
typename IdxFunction>
322void 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);
341template <
typename F1,
typename F2>
342void 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);
367template <
typename F1,
typename F2,
typename F3>
368void 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);
400template <
typename F1,
typename F2,
typename F3,
typename F4>
401void 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);