File: ThreadPool.h

package info (click to toggle)
llvm-toolchain-3.9 1%3A3.9.1-8
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 441,060 kB
  • ctags: 428,777
  • sloc: cpp: 2,546,577; ansic: 538,318; asm: 119,677; objc: 103,316; python: 102,148; sh: 27,847; pascal: 5,626; ml: 5,510; perl: 5,293; lisp: 4,801; makefile: 2,177; xml: 686; cs: 362; php: 212; csh: 117
file content (137 lines) | stat: -rw-r--r-- 4,236 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//===-- llvm/Support/ThreadPool.h - A ThreadPool implementation -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a crude C++11 based thread pool.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_THREAD_POOL_H
#define LLVM_SUPPORT_THREAD_POOL_H

#include "llvm/Support/thread.h"

#ifdef _MSC_VER
// concrt.h depends on eh.h for __uncaught_exception declaration
// even if we disable exceptions.
#include <eh.h>

// Disable warnings from ppltasks.h transitively included by <future>.
#pragma warning(push)
#pragma warning(disable:4530)
#pragma warning(disable:4062)
#endif

#include <future>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <utility>

namespace llvm {

/// A ThreadPool for asynchronous parallel execution on a defined number of
/// threads.
///
/// The pool keeps a vector of threads alive, waiting on a condition variable
/// for some work to become available.
class ThreadPool {
public:
#ifndef _MSC_VER
  using VoidTy = void;
  using TaskTy = std::function<void()>;
  using PackagedTaskTy = std::packaged_task<void()>;
#else
  // MSVC 2013 has a bug and can't use std::packaged_task<void()>;
  // We force it to use bool(bool) instead.
  using VoidTy = bool;
  using TaskTy = std::function<bool(bool)>;
  using PackagedTaskTy = std::packaged_task<bool(bool)>;
#endif

  /// Construct a pool with the number of core available on the system (or
  /// whatever the value returned by std::thread::hardware_concurrency() is).
  ThreadPool();

  /// Construct a pool of \p ThreadCount threads
  ThreadPool(unsigned ThreadCount);

  /// Blocking destructor: the pool will wait for all the threads to complete.
  ~ThreadPool();

  /// Asynchronous submission of a task to the pool. The returned future can be
  /// used to wait for the task to finish and is *non-blocking* on destruction.
  template <typename Function, typename... Args>
  inline std::shared_future<VoidTy> async(Function &&F, Args &&... ArgList) {
    auto Task =
        std::bind(std::forward<Function>(F), std::forward<Args>(ArgList)...);
#ifndef _MSC_VER
    return asyncImpl(std::move(Task));
#else
    // This lambda has to be marked mutable because MSVC 2013's std::bind call
    // operator isn't const qualified.
    return asyncImpl([Task](VoidTy) mutable -> VoidTy {
      Task();
      return VoidTy();
    });
#endif
  }

  /// Asynchronous submission of a task to the pool. The returned future can be
  /// used to wait for the task to finish and is *non-blocking* on destruction.
  template <typename Function>
  inline std::shared_future<VoidTy> async(Function &&F) {
#ifndef _MSC_VER
    return asyncImpl(std::forward<Function>(F));
#else
    return asyncImpl([F] (VoidTy) -> VoidTy { F(); return VoidTy(); });
#endif
  }

  /// Blocking wait for all the threads to complete and the queue to be empty.
  /// It is an error to try to add new tasks while blocking on this call.
  void wait();

private:
  /// Asynchronous submission of a task to the pool. The returned future can be
  /// used to wait for the task to finish and is *non-blocking* on destruction.
  std::shared_future<VoidTy> asyncImpl(TaskTy F);

  /// Threads in flight
  std::vector<llvm::thread> Threads;

  /// Tasks waiting for execution in the pool.
  std::queue<PackagedTaskTy> Tasks;

  /// Locking and signaling for accessing the Tasks queue.
  std::mutex QueueLock;
  std::condition_variable QueueCondition;

  /// Locking and signaling for job completion
  std::mutex CompletionLock;
  std::condition_variable CompletionCondition;

  /// Keep track of the number of thread actually busy
  std::atomic<unsigned> ActiveThreads;

#if LLVM_ENABLE_THREADS // avoids warning for unused variable
  /// Signal for the destruction of the pool, asking thread to exit.
  bool EnableFlag;
#endif
};
}

#endif // LLVM_SUPPORT_THREAD_POOL_H