14#ifndef __THREADS_POOL_H_
15#define __THREADS_POOL_H_
18#include <condition_variable>
27#if defined(__unix__) || defined(__APPLE__)
29#define MAESTRO_POOL_FORK_HANDLERS 1
37#ifdef MAESTRO_POOL_FORK_HANDLERS
48 virtual ~ForkAwarePool() =
default;
49 virtual void PrepareFork() = 0;
50 virtual void AfterForkParent() = 0;
51 virtual void AfterForkChild() = 0;
57 static PoolForkRegistry &Instance()
60 static auto *registry =
new PoolForkRegistry;
64 void Add(ForkAwarePool *pool)
66 std::call_once(installed, [] { pthread_atfork(&Prepare, &Parent, &Child); });
67 const std::lock_guard lock(mutex);
68 pools.push_back(pool);
71 void Remove(ForkAwarePool *pool)
73 const std::lock_guard lock(mutex);
74 pools.erase(std::remove(pools.begin(), pools.end(), pool), pools.end());
81 auto ®istry = Instance();
82 registry.mutex.lock();
83 for (
auto *pool : registry.pools)
89 auto ®istry = Instance();
90 for (
auto *pool : registry.pools)
91 pool->AfterForkParent();
92 registry.mutex.unlock();
97 auto ®istry = Instance();
98 for (
auto *pool : registry.pools)
99 pool->AfterForkChild();
100 registry.mutex.unlock();
104 std::vector<ForkAwarePool *> pools;
105 std::once_flag installed;
123#ifdef MAESTRO_POOL_FORK_HANDLERS
124 :
private Private::ForkAwarePool
143 for (
int i = 0; i < nrThreads; ++i)
144 Threads.emplace_back(std::make_unique<JobWorkerThread>(
this));
145#ifdef MAESTRO_POOL_FORK_HANDLERS
146 Private::PoolForkRegistry::Instance().Add(
this);
161#ifdef MAESTRO_POOL_FORK_HANDLERS
162 Private::PoolForkRegistry::Instance().Remove(
this);
175 const std::lock_guard lifecycle(LifecycleMutex);
177 std::lock_guard lock(Mutex);
179 for (
auto &worker : Threads)
180 worker->SetStopUnlocked();
185 for (
auto &worker : Threads)
198 for (
auto &worker : Threads)
212 std::lock_guard lock(Mutex);
229 std::lock_guard lock(Mutex);
230 JobsQueue.push(std::move(job));
248 std::unique_lock lock(FinishMutex);
250 if (FinishCount >= FinishLimit)
253 ConditionFinish.wait(lock, [
this] {
return FinishCount >= FinishLimit; });
255 if (FinishCount >= FinishLimit)
275 const std::lock_guard lifecycle(LifecycleMutex);
276 size_t oldSize = Threads.size();
278 if (oldSize == nrThreads)
281 if (oldSize < nrThreads)
283 for (
size_t i = oldSize; i < nrThreads; ++i)
285 Threads.emplace_back(std::make_unique<JobWorkerThread>(
this));
286 Threads.back()->Start();
292 std::lock_guard lock(Mutex);
293 for (
size_t i = nrThreads; i < oldSize; ++i)
294 Threads[i]->SetStopUnlocked();
299 for (
size_t i = nrThreads; i < oldSize; ++i)
301 Threads.resize(nrThreads);
317 std::unique_lock lock(FinishMutex);
323#ifdef MAESTRO_POOL_FORK_HANDLERS
324 void PrepareFork()
override
327 LifecycleMutex.lock();
330 idleAtFork = JobsQueue.empty() && Running == 0;
333 void AfterForkParent()
override
335 FinishMutex.unlock();
337 LifecycleMutex.unlock();
340 void AfterForkChild()
override
348 for (
auto &worker : Threads)
351 new (&Condition) std::condition_variable;
353 new (&ConditionFinish) std::condition_variable;
354 new (&FinishMutex) std::mutex;
355 new (&Mutex) std::mutex;
356 new (&LifecycleMutex) std::mutex;
365 inline void NotifyOne()
367 Condition.notify_one();
376 inline void NotifyAll()
378 Condition.notify_all();
387 inline bool HasWork()
const
389 return !JobsQueue.empty();
401 ConditionFinish.notify_all();
404 std::mutex LifecycleMutex;
406 std::condition_variable Condition;
408 std::mutex FinishMutex;
409 std::condition_variable ConditionFinish;
412 size_t FinishCount = 0;
413 size_t FinishLimit = std::numeric_limits<size_t>::max();
416 std::queue<std::shared_ptr<Job>> JobsQueue;
418 bool idleAtFork =
false;
420 std::vector<std::unique_ptr<JobWorkerThread>> Threads;
void Start()
Start all the threads in the threads pool.
void AddRunJob(const std::shared_ptr< Job > &job)
Add a job to be executed by the threads pool.
ThreadsPool(const ThreadsPool &)=delete
void WaitForFinish()
Wait for all jobs to finish.
void SetFinishLimit(size_t limit)
Set the finish limit.
void AddRunJob(std::shared_ptr< Job > &&job)
Add a job to be executed by the threads pool.
void Resize(size_t nrThreads)
Resize the threads pool.
ThreadsPool & operator=(const ThreadsPool &)=delete
void Stop()
Stop all the threads in the threads pool.
~ThreadsPool()
Destructor.
ThreadsPool(int nrThreads=0)
Construct a new Thread pool object.
WorkerThread class for a thread in a threads pool.
Portable dense contraction kernels.