scc 2026.07
SystemC components library
thread_syncronizer.h
1/*******************************************************************************
2 * Copyright 2017 MINRES Technologies GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16
17#ifndef _THREAD_SYNCRONIZER_H_
18#define _THREAD_SYNCRONIZER_H_
19
20#include <atomic>
21#include <functional>
22#include <future>
23#include <rigtorp/SPSCQueue.h>
24#include <stdexcept>
25#include <thread>
26
28
32namespace util {
37private:
38 static constexpr size_t default_queue_capacity = 1024;
39
40 using task_type = std::function<void()>;
41
43 std::atomic<bool> ready{false};
44 std::atomic<bool> running{true};
45
46public:
50 explicit thread_syncronizer(size_t queue_capacity = default_queue_capacity)
51 : tasks_(queue_capacity) {}
52
56 ready.store(false, std::memory_order_release);
57 running.store(false, std::memory_order_release);
58 }
59
64 bool is_ready() { return ready.load(std::memory_order_acquire); }
72#if __cplusplus > 201402L
73 template <class F, class... Args> typename std::invoke_result<F, Args...>::type enqueue_and_wait(F&& f, Args&&... args) {
74#else
75 template <class F, class... Args> typename std::result_of<F(Args...)>::type enqueue_and_wait(F&& f, Args&&... args) {
76#endif
77 auto res = enqueue(f, args...);
78 res.wait();
79 return res.get();
80 }
81
88#if __cplusplus > 201402L
89 template <class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result<F, Args...>::type> {
90 using return_type = typename std::invoke_result<F, Args...>::type;
91#else
92 template <class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
93 using return_type = typename std::result_of<F(Args...)>::type;
94#endif
95 auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
96
97 std::future<return_type> res = task->get_future();
98 while(running.load(std::memory_order_acquire)) {
99 if(tasks_.try_emplace([task]() { (*task)(); })) {
100 return res;
101 }
102 std::this_thread::yield();
103 }
104 throw std::runtime_error("thread_syncronizer is shutting down");
105 }
106
109 void execute() {
110 if(auto* pending = tasks_.front()) {
111 // Move the task out before popping so the queue slot can be released
112 // immediately after the callback has been taken over locally.
113 task_type functor = std::move(*pending);
114 tasks_.pop();
115 try {
116 functor();
117 } catch(...) {
118 } // Suppress all exceptions.
119 }
120 }
121
124 void executeNext() {
125 ready.store(true, std::memory_order_release);
126 while(running.load(std::memory_order_acquire) && ready.load(std::memory_order_acquire)) {
127 if(tasks_.front()) {
128 execute();
129 break;
130 }
131 std::this_thread::yield();
132 }
133 ready.store(false, std::memory_order_release);
134 }
135};
136} // namespace util
138#endif /* _THREAD_SYNCRONIZER_H_ */
auto enqueue(F &&f, Args &&... args) -> std::future< typename std::result_of< F(Args...)>::type >
std::result_of< F(Args...)>::type enqueue_and_wait(F &&f, Args &&... args)
thread_syncronizer(size_t queue_capacity=default_queue_capacity)
SCC common utilities.
Definition bit_field.h:30