/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Support/ThreadPool.cpp
Line | Count | Source |
1 | | //==-- llvm/Support/ThreadPool.cpp - 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 implements a crude C++11 based thread pool. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/Support/ThreadPool.h" |
15 | | |
16 | | #include "llvm/Config/llvm-config.h" |
17 | | #include "llvm/Support/raw_ostream.h" |
18 | | |
19 | | using namespace llvm; |
20 | | |
21 | | #if LLVM_ENABLE_THREADS |
22 | | |
23 | | // Default to std::thread::hardware_concurrency |
24 | 7 | ThreadPool::ThreadPool() : ThreadPool(std::thread::hardware_concurrency()) {} Unexecuted instantiation: llvm::ThreadPool::ThreadPool() llvm::ThreadPool::ThreadPool() Line | Count | Source | 24 | 7 | ThreadPool::ThreadPool() : ThreadPool(std::thread::hardware_concurrency()) {} |
|
25 | | |
26 | | ThreadPool::ThreadPool(unsigned ThreadCount) |
27 | 115 | : ActiveThreads(0), EnableFlag(true) { |
28 | 115 | // Create ThreadCount threads that will loop forever, wait on QueueCondition |
29 | 115 | // for tasks to be queued or the Pool to be destroyed. |
30 | 115 | Threads.reserve(ThreadCount); |
31 | 360 | for (unsigned ThreadID = 0; ThreadID < ThreadCount360 ; ++ThreadID245 ) { |
32 | 245 | Threads.emplace_back([&] { |
33 | 471 | while (true471 ) { |
34 | 469 | PackagedTaskTy Task; |
35 | 469 | { |
36 | 469 | std::unique_lock<std::mutex> LockGuard(QueueLock); |
37 | 469 | // Wait for tasks to be pushed in the queue |
38 | 469 | QueueCondition.wait(LockGuard, |
39 | 793 | [&] { return !EnableFlag || 793 !Tasks.empty()522 ; }); |
40 | 469 | // Exit condition |
41 | 469 | if (!EnableFlag && 469 Tasks.empty()271 ) |
42 | 243 | return; |
43 | 226 | // Yeah, we have a task, grab it and release the lock on the queue |
44 | 226 | |
45 | 226 | // We first need to signal that we are active before popping the queue |
46 | 226 | // in order for wait() to properly detect that even if the queue is |
47 | 226 | // empty, there is still a task in flight. |
48 | 226 | { |
49 | 226 | ++ActiveThreads; |
50 | 226 | std::unique_lock<std::mutex> LockGuard(CompletionLock); |
51 | 226 | } |
52 | 226 | Task = std::move(Tasks.front()); |
53 | 226 | Tasks.pop(); |
54 | 226 | } |
55 | 226 | // Run the task we just grabbed |
56 | 226 | Task(); |
57 | 226 | |
58 | 226 | { |
59 | 226 | // Adjust `ActiveThreads`, in case someone waits on ThreadPool::wait() |
60 | 226 | std::unique_lock<std::mutex> LockGuard(CompletionLock); |
61 | 226 | --ActiveThreads; |
62 | 226 | } |
63 | 226 | |
64 | 226 | // Notify task completion, in case someone waits on ThreadPool::wait() |
65 | 226 | CompletionCondition.notify_all(); |
66 | 226 | } |
67 | 245 | }); |
68 | 245 | } |
69 | 115 | } |
70 | | |
71 | 97 | void ThreadPool::wait() { |
72 | 97 | // Wait for all threads to complete and the queue to be empty |
73 | 97 | std::unique_lock<std::mutex> LockGuard(CompletionLock); |
74 | 97 | // The order of the checks for ActiveThreads and Tasks.empty() matters because |
75 | 97 | // any active threads might be modifying the Tasks queue, and this would be a |
76 | 97 | // race. |
77 | 97 | CompletionCondition.wait(LockGuard, |
78 | 229 | [&] { return !ActiveThreads && 229 Tasks.empty()147 ; }); |
79 | 97 | } |
80 | | |
81 | 226 | std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) { |
82 | 226 | /// Wrap the Task in a packaged_task to return a future object. |
83 | 226 | PackagedTaskTy PackagedTask(std::move(Task)); |
84 | 226 | auto Future = PackagedTask.get_future(); |
85 | 226 | { |
86 | 226 | // Lock the queue and push the new task |
87 | 226 | std::unique_lock<std::mutex> LockGuard(QueueLock); |
88 | 226 | |
89 | 226 | // Don't allow enqueueing after disabling the pool |
90 | 226 | assert(EnableFlag && "Queuing a thread during ThreadPool destruction"); |
91 | 226 | |
92 | 226 | Tasks.push(std::move(PackagedTask)); |
93 | 226 | } |
94 | 226 | QueueCondition.notify_one(); |
95 | 226 | return Future.share(); |
96 | 226 | } |
97 | | |
98 | | // The destructor joins all threads, waiting for completion. |
99 | 115 | ThreadPool::~ThreadPool() { |
100 | 115 | { |
101 | 115 | std::unique_lock<std::mutex> LockGuard(QueueLock); |
102 | 115 | EnableFlag = false; |
103 | 115 | } |
104 | 115 | QueueCondition.notify_all(); |
105 | 115 | for (auto &Worker : Threads) |
106 | 242 | Worker.join(); |
107 | 115 | } |
108 | | |
109 | | #else // LLVM_ENABLE_THREADS Disabled |
110 | | |
111 | | ThreadPool::ThreadPool() : ThreadPool(0) {} |
112 | | |
113 | | // No threads are launched, issue a warning if ThreadCount is not 0 |
114 | | ThreadPool::ThreadPool(unsigned ThreadCount) |
115 | | : ActiveThreads(0) { |
116 | | if (ThreadCount) { |
117 | | errs() << "Warning: request a ThreadPool with " << ThreadCount |
118 | | << " threads, but LLVM_ENABLE_THREADS has been turned off\n"; |
119 | | } |
120 | | } |
121 | | |
122 | | void ThreadPool::wait() { |
123 | | // Sequential implementation running the tasks |
124 | | while (!Tasks.empty()) { |
125 | | auto Task = std::move(Tasks.front()); |
126 | | Tasks.pop(); |
127 | | Task(); |
128 | | } |
129 | | } |
130 | | |
131 | | std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) { |
132 | | // Get a Future with launch::deferred execution using std::async |
133 | | auto Future = std::async(std::launch::deferred, std::move(Task)).share(); |
134 | | // Wrap the future so that both ThreadPool::wait() can operate and the |
135 | | // returned future can be sync'ed on. |
136 | | PackagedTaskTy PackagedTask([Future]() { Future.get(); }); |
137 | | Tasks.push(std::move(PackagedTask)); |
138 | | return Future; |
139 | | } |
140 | | |
141 | | ThreadPool::~ThreadPool() { |
142 | | wait(); |
143 | | } |
144 | | |
145 | | #endif |