Home | History | Annotate | Download | only in Support
      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 #include <future>
     20 
     21 #include <atomic>
     22 #include <condition_variable>
     23 #include <functional>
     24 #include <memory>
     25 #include <mutex>
     26 #include <queue>
     27 #include <utility>
     28 
     29 namespace llvm {
     30 
     31 /// A ThreadPool for asynchronous parallel execution on a defined number of
     32 /// threads.
     33 ///
     34 /// The pool keeps a vector of threads alive, waiting on a condition variable
     35 /// for some work to become available.
     36 class ThreadPool {
     37 public:
     38 #ifndef _MSC_VER
     39   using VoidTy = void;
     40   using TaskTy = std::function<void()>;
     41   using PackagedTaskTy = std::packaged_task<void()>;
     42 #else
     43   // MSVC 2013 has a bug and can't use std::packaged_task<void()>;
     44   // We force it to use bool(bool) instead.
     45   using VoidTy = bool;
     46   using TaskTy = std::function<bool(bool)>;
     47   using PackagedTaskTy = std::packaged_task<bool(bool)>;
     48 #endif
     49 
     50   /// Construct a pool with the number of core available on the system (or
     51   /// whatever the value returned by std::thread::hardware_concurrency() is).
     52   ThreadPool();
     53 
     54   /// Construct a pool of \p ThreadCount threads
     55   ThreadPool(unsigned ThreadCount);
     56 
     57   /// Blocking destructor: the pool will wait for all the threads to complete.
     58   ~ThreadPool();
     59 
     60   /// Asynchronous submission of a task to the pool. The returned future can be
     61   /// used to wait for the task to finish and is *non-blocking* on destruction.
     62   template <typename Function, typename... Args>
     63   inline std::shared_future<VoidTy> async(Function &&F, Args &&... ArgList) {
     64     auto Task =
     65         std::bind(std::forward<Function>(F), std::forward<Args>(ArgList)...);
     66 #ifndef _MSC_VER
     67     return asyncImpl(std::move(Task));
     68 #else
     69     // This lambda has to be marked mutable because MSVC 2013's std::bind call
     70     // operator isn't const qualified.
     71     return asyncImpl([Task](VoidTy) mutable -> VoidTy {
     72       Task();
     73       return VoidTy();
     74     });
     75 #endif
     76   }
     77 
     78   /// Asynchronous submission of a task to the pool. The returned future can be
     79   /// used to wait for the task to finish and is *non-blocking* on destruction.
     80   template <typename Function>
     81   inline std::shared_future<VoidTy> async(Function &&F) {
     82 #ifndef _MSC_VER
     83     return asyncImpl(std::forward<Function>(F));
     84 #else
     85     return asyncImpl([F] (VoidTy) -> VoidTy { F(); return VoidTy(); });
     86 #endif
     87   }
     88 
     89   /// Blocking wait for all the threads to complete and the queue to be empty.
     90   /// It is an error to try to add new tasks while blocking on this call.
     91   void wait();
     92 
     93 private:
     94   /// Asynchronous submission of a task to the pool. The returned future can be
     95   /// used to wait for the task to finish and is *non-blocking* on destruction.
     96   std::shared_future<VoidTy> asyncImpl(TaskTy F);
     97 
     98   /// Threads in flight
     99   std::vector<llvm::thread> Threads;
    100 
    101   /// Tasks waiting for execution in the pool.
    102   std::queue<PackagedTaskTy> Tasks;
    103 
    104   /// Locking and signaling for accessing the Tasks queue.
    105   std::mutex QueueLock;
    106   std::condition_variable QueueCondition;
    107 
    108   /// Locking and signaling for job completion
    109   std::mutex CompletionLock;
    110   std::condition_variable CompletionCondition;
    111 
    112   /// Keep track of the number of thread actually busy
    113   std::atomic<unsigned> ActiveThreads;
    114 
    115 #if LLVM_ENABLE_THREADS // avoids warning for unused variable
    116   /// Signal for the destruction of the pool, asking thread to exit.
    117   bool EnableFlag;
    118 #endif
    119 };
    120 }
    121 
    122 #endif // LLVM_SUPPORT_THREAD_POOL_H
    123