1 //===-- llvm/Support/ThreadPool.h - A ThreadPool implementation -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines a crude C++11 based thread pool. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_SUPPORT_THREAD_POOL_H 15 #define LLVM_SUPPORT_THREAD_POOL_H 16 17 #include "llvm/Support/thread.h" 18 19 #ifdef _MSC_VER 20 // concrt.h depends on eh.h for __uncaught_exception declaration 21 // even if we disable exceptions. 22 #include <eh.h> 23 24 // Disable warnings from ppltasks.h transitively included by <future>. 25 #pragma warning(push) 26 #pragma warning(disable:4530) 27 #pragma warning(disable:4062) 28 #endif 29 30 #include <future> 31 32 #ifdef _MSC_VER 33 #pragma warning(pop) 34 #endif 35 36 #include <condition_variable> 37 #include <functional> 38 #include <memory> 39 #include <mutex> 40 #include <queue> 41 #include <utility> 42 43 namespace llvm { 44 45 /// A ThreadPool for asynchronous parallel execution on a defined number of 46 /// threads. 47 /// 48 /// The pool keeps a vector of threads alive, waiting on a condition variable 49 /// for some work to become available. 50 class ThreadPool { 51 public: 52 #ifndef _MSC_VER 53 using VoidTy = void; 54 using TaskTy = std::function<void()>; 55 using PackagedTaskTy = std::packaged_task<void()>; 56 #else 57 // MSVC 2013 has a bug and can't use std::packaged_task<void()>; 58 // We force it to use bool(bool) instead. 59 using VoidTy = bool; 60 using TaskTy = std::function<bool(bool)>; 61 using PackagedTaskTy = std::packaged_task<bool(bool)>; 62 #endif 63 64 /// Construct a pool with the number of core available on the system (or 65 /// whatever the value returned by std::thread::hardware_concurrency() is). 66 ThreadPool(); 67 68 /// Construct a pool of \p ThreadCount threads 69 ThreadPool(unsigned ThreadCount); 70 71 /// Blocking destructor: the pool will wait for all the threads to complete. 72 ~ThreadPool(); 73 74 /// Asynchronous submission of a task to the pool. The returned future can be 75 /// used to wait for the task to finish and is *non-blocking* on destruction. 76 template <typename Function, typename... Args> async(Function && F,Args &&...ArgList)77 inline std::shared_future<VoidTy> async(Function &&F, Args &&... ArgList) { 78 auto Task = 79 std::bind(std::forward<Function>(F), std::forward<Args>(ArgList)...); 80 #ifndef _MSC_VER 81 return asyncImpl(std::move(Task)); 82 #else 83 // This lambda has to be marked mutable because MSVC 2013's std::bind call 84 // operator isn't const qualified. 85 return asyncImpl([Task](VoidTy) mutable -> VoidTy { 86 Task(); 87 return VoidTy(); 88 }); 89 #endif 90 } 91 92 /// Asynchronous submission of a task to the pool. The returned future can be 93 /// used to wait for the task to finish and is *non-blocking* on destruction. 94 template <typename Function> async(Function && F)95 inline std::shared_future<VoidTy> async(Function &&F) { 96 #ifndef _MSC_VER 97 return asyncImpl(std::forward<Function>(F)); 98 #else 99 return asyncImpl([F] (VoidTy) -> VoidTy { F(); return VoidTy(); }); 100 #endif 101 } 102 103 /// Blocking wait for all the threads to complete and the queue to be empty. 104 /// It is an error to try to add new tasks while blocking on this call. 105 void wait(); 106 107 private: 108 /// Asynchronous submission of a task to the pool. The returned future can be 109 /// used to wait for the task to finish and is *non-blocking* on destruction. 110 std::shared_future<VoidTy> asyncImpl(TaskTy F); 111 112 /// Threads in flight 113 std::vector<llvm::thread> Threads; 114 115 /// Tasks waiting for execution in the pool. 116 std::queue<PackagedTaskTy> Tasks; 117 118 /// Locking and signaling for accessing the Tasks queue. 119 std::mutex QueueLock; 120 std::condition_variable QueueCondition; 121 122 /// Locking and signaling for job completion 123 std::mutex CompletionLock; 124 std::condition_variable CompletionCondition; 125 126 /// Keep track of the number of thread actually busy 127 std::atomic<unsigned> ActiveThreads; 128 129 #if LLVM_ENABLE_THREADS // avoids warning for unused variable 130 /// Signal for the destruction of the pool, asking thread to exit. 131 bool EnableFlag; 132 #endif 133 }; 134 } 135 136 #endif // LLVM_SUPPORT_THREAD_POOL_H 137