Index: include/llvm/Support/ThreadPool.h =================================================================== --- include/llvm/Support/ThreadPool.h +++ include/llvm/Support/ThreadPool.h @@ -117,15 +117,12 @@ std::queue 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::mutex Mutex; + std::condition_variable SubmissionCondition; std::condition_variable CompletionCondition; /// Keep track of the number of thread actually busy - std::atomic ActiveThreads; + unsigned ActiveThreads; #if LLVM_ENABLE_THREADS // avoids warning for unused variable /// Signal for the destruction of the pool, asking thread to exit. Index: lib/Support/ThreadPool.cpp =================================================================== --- lib/Support/ThreadPool.cpp +++ lib/Support/ThreadPool.cpp @@ -25,18 +25,18 @@ ThreadPool::ThreadPool(unsigned ThreadCount) : ActiveThreads(0), EnableFlag(true) { - // Create ThreadCount threads that will loop forever, wait on QueueCondition - // for tasks to be queued or the Pool to be destroyed. + // Create ThreadCount threads that will loop forever, wait on + // SubmissionCondition for tasks to be queued or the Pool to be destroyed. Threads.reserve(ThreadCount); for (unsigned ThreadID = 0; ThreadID < ThreadCount; ++ThreadID) { Threads.emplace_back([&] { while (true) { PackagedTaskTy Task; { - std::unique_lock LockGuard(QueueLock); + std::unique_lock LockGuard(Mutex); // Wait for tasks to be pushed in the queue - QueueCondition.wait(LockGuard, - [&] { return !EnableFlag || !Tasks.empty(); }); + SubmissionCondition.wait( + LockGuard, [&] { return !EnableFlag || !Tasks.empty(); }); // Exit condition if (!EnableFlag && Tasks.empty()) return; @@ -45,10 +45,7 @@ // We first need to signal that we are active before popping the queue // in order for wait() to properly detect that even if the queue is // empty, there is still a task in flight. - { - ++ActiveThreads; - std::unique_lock LockGuard(CompletionLock); - } + ++ActiveThreads; Task = std::move(Tasks.front()); Tasks.pop(); } @@ -61,7 +58,7 @@ { // Adjust `ActiveThreads`, in case someone waits on ThreadPool::wait() - std::unique_lock LockGuard(CompletionLock); + std::unique_lock LockGuard(Mutex); --ActiveThreads; } @@ -74,7 +71,7 @@ void ThreadPool::wait() { // Wait for all threads to complete and the queue to be empty - std::unique_lock LockGuard(CompletionLock); + std::unique_lock LockGuard(Mutex); CompletionCondition.wait(LockGuard, [&] { return Tasks.empty() && !ActiveThreads; }); } @@ -85,24 +82,24 @@ auto Future = PackagedTask.get_future(); { // Lock the queue and push the new task - std::unique_lock LockGuard(QueueLock); + std::unique_lock LockGuard(Mutex); // Don't allow enqueueing after disabling the pool assert(EnableFlag && "Queuing a thread during ThreadPool destruction"); Tasks.push(std::move(PackagedTask)); } - QueueCondition.notify_one(); + SubmissionCondition.notify_one(); return Future.share(); } // The destructor joins all threads, waiting for completion. ThreadPool::~ThreadPool() { { - std::unique_lock LockGuard(QueueLock); + std::unique_lock LockGuard(Mutex); EnableFlag = false; } - QueueCondition.notify_all(); + SubmissionCondition.notify_all(); for (auto &Worker : Threads) Worker.join(); }