scc  2022.4.0
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 
30 namespace util {
35 private:
36  std::queue<std::function<void()>> tasks_;
37  std::atomic<bool> ready;
38  std::mutex mutex_;
39  std::condition_variable condition_;
40 
41 public:
45  thread_syncronizer() = default;
50  // Set running flag to false then notify all threads.
51  condition_.notify_all();
52  }
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  }
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  }
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  }
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_ */
executes a function syncronized in another thread
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