LibraryLink Utilities  3.0.1
Modern C++ wrapper over LibraryLink and WSTP
Async/Utilities.h
Go to the documentation of this file.
1 
6 #ifndef LLU_ASYNC_UTILITIES_H
7 #define LLU_ASYNC_UTILITIES_H
8 
9 #include <functional>
10 #include <future>
11 #include <memory>
12 #include <thread>
13 #include <vector>
14 
15 namespace LLU::Async {
16 
24  struct TypeErasedCallableBase {
25  virtual void call() = 0;
26  virtual ~TypeErasedCallableBase() = default;
27  };
28 
33  template<typename F>
34  struct TypeErasedCallable : TypeErasedCallableBase {
35  explicit TypeErasedCallable(F&& f) : callable(std::forward<F>(f)) {}
36 
37  void call() override {
38  callable();
39  }
40  F callable;
41  };
42 
43  public:
49  template<typename F, typename = std::enable_if_t<!std::is_same_v<std::remove_cv<F>, FunctionWrapper>>>
50  explicit FunctionWrapper(F&& f) : impl {std::make_unique<TypeErasedCallable<F>>(std::forward<F>(f))} {}
51 
59  template<typename F, typename... Args>
60  explicit FunctionWrapper(F&& f, Args&&... args) {
61  auto boundF = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
62  impl = std::make_unique<TypeErasedCallable<F>>(std::move(boundF));
63  }
64 
66  FunctionWrapper() = default;
67  FunctionWrapper(FunctionWrapper&& other) noexcept = default;
68  FunctionWrapper& operator=(FunctionWrapper&& other) noexcept = default;
69  FunctionWrapper(const FunctionWrapper&) = delete;
70  FunctionWrapper& operator=(const FunctionWrapper&) = delete;
71  ~FunctionWrapper() = default;
73 
75  void operator()() {
76  impl->call();
77  }
78 
79  private:
81  std::unique_ptr<TypeErasedCallableBase> impl = nullptr;
82  };
83 
91  class ThreadJoiner {
92  std::vector<std::thread>& threads;
93 
94  public:
99  explicit ThreadJoiner(std::vector<std::thread>& threadsToJoin) : threads(threadsToJoin) {}
100 
101  ThreadJoiner(const ThreadJoiner&) = delete;
102  ThreadJoiner& operator=(const ThreadJoiner&) = delete;
103  ThreadJoiner(ThreadJoiner&&) = delete;
104  ThreadJoiner& operator=(ThreadJoiner&&) = delete;
105 
108  for (auto& t : threads) {
109  if (t.joinable()) {
110  t.join();
111  }
112  }
113  }
114  };
115 
124  template<typename FunctionType, typename... Args>
125  std::packaged_task<std::invoke_result_t<FunctionType, Args...>()> getPackagedTask(FunctionType&& f, Args&&... args) {
126  using result_type = std::invoke_result_t<FunctionType, Args...>;
127  // NOLINTNEXTLINE(modernize-avoid-bind): perfect forwarding capture of a parameter pack in a lambda is not trivial
128  auto boundF = std::bind(std::forward<FunctionType>(f), std::forward<Args>(args)...);
129  return std::packaged_task<result_type()> {std::move(boundF)};
130  }
131 
136  class Pausable {
137  std::atomic_bool pausedQ = false;
138  std::mutex workersMutex;
139  std::condition_variable pausedWorkers;
140  public:
141 
144  void checkPause() {
145  if (pausedQ) {
146  std::unique_lock lck {workersMutex};
147  pausedWorkers.wait(lck, [&]() -> bool { return !pausedQ; });
148  }
149  }
150 
152  void pause() noexcept {
153  pausedQ = true;
154  }
155 
157  void resume() noexcept {
158  pausedQ = false;
159  pausedWorkers.notify_all();
160  }
161  };
162 } // namespace LLU::Async
163 
164 #endif // LLU_ASYNC_UTILITIES_H
LLU::Async::FunctionWrapper::FunctionWrapper
FunctionWrapper(F &&f)
Create a FunctionWrapper from any callable object by performing type-erasure.
Definition: Async/Utilities.h:50
LLU::Async::Pausable
Utility class for pausable task queues.
Definition: Async/Utilities.h:136
LLU::Async::FunctionWrapper
Wraps an arbitrary callable object (possibly binding its arguments) to be evaluated later....
Definition: Async/Utilities.h:22
LLU::Async::getPackagedTask
std::packaged_task< std::invoke_result_t< FunctionType, Args... >)> getPackagedTask(FunctionType &&f, Args &&... args)
Create a std::packaged_task from a callable object and arguments to it.
Definition: Async/Utilities.h:125
LLU::Async::Pausable::resume
void resume() noexcept
Signal to resume work and notify waiting worker threads.
Definition: Async/Utilities.h:157
LLU::Async::Pausable::checkPause
void checkPause()
This is the function worker threads will call to see if the work has been paused.
Definition: Async/Utilities.h:144
LLU::Async::ThreadJoiner
A guard for a vector of threads to make sure they are joined before their destruction....
Definition: Async/Utilities.h:91
LLU::Async::ThreadJoiner::ThreadJoiner
ThreadJoiner(std::vector< std::thread > &threadsToJoin)
Create a ThreadJoiner from a reference to a vector of threads.
Definition: Async/Utilities.h:99
LLU::Async::FunctionWrapper::operator()
void operator()()
Call the internal callable object.
Definition: Async/Utilities.h:75
LLU::Async::FunctionWrapper::FunctionWrapper
FunctionWrapper(F &&f, Args &&... args)
Create a FunctionWrapper from a callable object and arguments for the call.
Definition: Async/Utilities.h:60
LLU::Async::ThreadJoiner::~ThreadJoiner
~ThreadJoiner()
The destuctor loops over the vector of threads and joins each one after checking if it is joinable.
Definition: Async/Utilities.h:107
LLU::Async::Pausable::pause
void pause() noexcept
Signal to pause work.
Definition: Async/Utilities.h:152