scc 2025.09
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 <queue>
24#include <stdexcept>
26
30namespace util {
35private:
36 std::queue<std::function<void()>> tasks_;
37 std::atomic<bool> ready;
38 std::mutex mutex_;
39 std::condition_variable condition_;
40
41public:
45 thread_syncronizer() = default;
50 // Set running flag to false then notify all threads.
51 condition_.notify_all();
52 }
53
58 bool is_ready() { return ready.load(std::memory_order_acquire); }
66 template <class F, class... Args> typename std::result_of<F(Args...)>::type enqueue_and_wait(F&& f, Args&&... args) {
67 auto res = enqueue(f, args...);
68 res.wait();
69 return res.get();
70 }
71
78 template <class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
79 using return_type = typename std::result_of<F(Args...)>::type;
80 auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
81
82 std::future<return_type> res = task->get_future();
83 {
84 std::unique_lock<std::mutex> lock(mutex_);
85 tasks_.emplace([task]() { (*task)(); });
86 }
87 condition_.notify_one();
88 return res;
89 }
90
93 void execute() {
94 if(tasks_.empty())
95 return;
96 {
97 std::unique_lock<std::mutex> lock(mutex_);
98 // Copy task locally and remove from the queue. This is done within
99 // its own scope so that the task object is destructed immediately
100 // after running the task. This is useful in the event that the
101 // function contains shared_ptr arguments bound via bind.
102 std::function<void()> functor = tasks_.front();
103 tasks_.pop();
104 lock.unlock();
105 // Run the task.
106 try {
107 functor();
108 } catch(...) {
109 } // Suppress all exceptions.
110 }
111 }
112
115 void executeNext() {
116 ready.store(true, std::memory_order_release);
117 // Wait on condition variable while the task is empty
118 std::unique_lock<std::mutex> lock(mutex_);
119 while(tasks_.empty() && ready.load(std::memory_order_acquire)) {
120 condition_.wait_for(lock, std::chrono::milliseconds(10));
121 }
122 lock.unlock();
123 execute();
124 ready.store(false, std::memory_order_release);
125 }
126};
127} // namespace util
129#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)
SCC common utilities.
Definition bit_field.h:30