10 #include <condition_variable>
23 # pragma clang diagnostic push
24 # pragma clang diagnostic ignored "-Wweak-vtables"
31 # pragma clang diagnostic pop
34 virtual ~Task() =
default;
35 virtual void run() = 0;
38 template<
typename Function>
39 struct FunctionHolder : Task
43 template<
typename FunctionFwd>
44 explicit FunctionHolder(FunctionFwd&& func) : m_func{std::forward<FunctionFwd>(func)}
55 using TaskPackage = std::pair<std::unique_ptr<Task>, std::promise<void>>;
61 std::unique_lock<std::mutex> lock{m_mutex};
66 if(m_thread.joinable())
68 if(std::this_thread::get_id() == m_thread.get_id())
70 std::cerr <<
"ERROR in ~CallbackThread: thread joins itself" << std::endl;
79 template<
typename NullaryFunction>
80 auto submit(NullaryFunction&& nf) -> std::future<void>
82 using DecayedFunction = std::decay_t<NullaryFunction>;
84 std::is_void_v<std::invoke_result_t<DecayedFunction>>,
85 "Submitted function must not have any arguments and return void.");
90 std::unique_ptr<Task>(
new FunctionHolder<DecayedFunction>{std::forward<NullaryFunction>(nf)}),
91 std::promise<void>{});
92 auto f = tp.second.get_future();
94 std::unique_lock<std::mutex> lock{m_mutex};
95 m_tasks.emplace(std::move(tp));
96 if(!m_thread.joinable())
111 std::unique_lock<std::mutex> lock{m_mutex};
112 return m_tasks.empty();
116 std::thread m_thread;
117 std::condition_variable m_cond;
120 std::queue<TaskPackage> m_tasks;
122 auto startWorkerThread() ->
void
124 m_thread = std::thread(
129 std::promise<void> taskPromise;
130 std::exception_ptr eptr;
133 std::unique_ptr<Task> task =
nullptr;
135 std::unique_lock<std::mutex> lock{m_mutex};
136 m_cond.wait(lock, [
this] {
return m_stop || !m_tasks.empty(); });
138 if(m_stop && m_tasks.empty())
141 task = std::move(m_tasks.front().first);
142 taskPromise = std::move(m_tasks.front().second);
151 eptr = std::current_exception();
154 std::unique_lock<std::mutex> lock{m_mutex};
164 taskPromise.set_exception(std::move(eptr));
166 taskPromise.set_value();
auto submit(NullaryFunction &&nf) -> std::future< void >
It is guaranteed that the task is fully destroyed before the future's result is set.