1 //===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/Parallel.h"
10 #include "llvm/Config/llvm-config.h"
12 #if LLVM_ENABLE_THREADS
14 #include "llvm/Support/Threading.h"
26 /// An abstract class that takes closures and runs them asynchronously.
29 virtual ~Executor() = default;
30 virtual void add(std::function
<void()> func
) = 0;
32 static Executor
*getDefaultExecutor();
35 /// An implementation of an Executor that runs closures on a thread pool
37 class ThreadPoolExecutor
: public Executor
{
39 explicit ThreadPoolExecutor(unsigned ThreadCount
= hardware_concurrency())
41 // Spawn all but one of the threads in another thread as spawning threads
43 std::thread([&, ThreadCount
] {
44 for (size_t i
= 1; i
< ThreadCount
; ++i
) {
45 std::thread([=] { work(); }).detach();
51 ~ThreadPoolExecutor() override
{
52 std::unique_lock
<std::mutex
> Lock(Mutex
);
59 void add(std::function
<void()> F
) override
{
60 std::unique_lock
<std::mutex
> Lock(Mutex
);
69 std::unique_lock
<std::mutex
> Lock(Mutex
);
70 Cond
.wait(Lock
, [&] { return Stop
|| !WorkStack
.empty(); });
73 auto Task
= WorkStack
.top();
81 std::atomic
<bool> Stop
{false};
82 std::stack
<std::function
<void()>> WorkStack
;
84 std::condition_variable Cond
;
85 parallel::detail::Latch Done
;
88 Executor
*Executor::getDefaultExecutor() {
89 static ThreadPoolExecutor exec
;
94 static std::atomic
<int> TaskGroupInstances
;
96 // Latch::sync() called by the dtor may cause one thread to block. If is a dead
97 // lock if all threads in the default executor are blocked. To prevent the dead
98 // lock, only allow the first TaskGroup to run tasks parallelly. In the scenario
99 // of nested parallel_for_each(), only the outermost one runs parallelly.
100 TaskGroup::TaskGroup() : Parallel(TaskGroupInstances
++ == 0) {}
101 TaskGroup::~TaskGroup() { --TaskGroupInstances
; }
103 void TaskGroup::spawn(std::function
<void()> F
) {
106 Executor::getDefaultExecutor()->add([&, F
] {
115 } // namespace detail
116 } // namespace parallel
118 #endif // LLVM_ENABLE_THREADS