// This code is in the public domain -- castano@gmail.com #pragma once #ifndef NV_THREAD_THREADPOOL_H #define NV_THREAD_THREADPOOL_H #include "nvthread.h" #include "Event.h" #include "Thread.h" // The thread pool creates one worker thread for each physical core. // The threads are idle waiting for their start events so that they do not consume any resources while inactive. // The thread pool runs the same function in all worker threads, the idea is to use this as the foundation of a custom task scheduler. // When the thread pool starts, the main thread continues running, but the common use case is to inmmediately wait for the termination events of the worker threads. // @@ The start and wait methods could probably be merged. // It may be running the thread function on the invoking thread to avoid thread switches. namespace nv { class Thread; class Event; typedef void ThreadTask(void * context, int id); class ThreadPool { NV_FORBID_COPY(ThreadPool); public: static void setup(uint workerCount, bool useThreadAffinity, bool useCallingThread); static ThreadPool * acquire(); static void release(ThreadPool *); ThreadPool(uint workerCount = processorCount(), bool useThreadAffinity = true, bool useCallingThread = false); ~ThreadPool(); void run(ThreadTask * func, void * arg); void start(ThreadTask * func, void * arg); void wait(); //NV_THREAD_LOCAL static uint threadId; private: static void workerFunc(void * arg); bool useThreadAffinity; bool useCallingThread; uint workerCount; Thread * workers; Event * startEvents; Event * finishEvents; uint allIdle; // Current function: ThreadTask * func; void * arg; }; #if NV_CC_CPP11 template void thread_pool_run(F f) { // Transform lambda into function pointer. auto lambda = [](void* context, int id) { F & f = *reinterpret_cast(context); f(id); }; ThreadPool * pool = ThreadPool::acquire(); pool->run(lambda, &f); ThreadPool::release(pool); } #endif // NV_CC_CPP11 } // namespace nv #endif // NV_THREAD_THREADPOOL_H