Determinic Concurrency


Loading...
Searching...
No Matches
UserControlledScheduler.h
Go to the documentation of this file.
1
13#pragma once
14#include <DeterministicConcurrency>
15#include <cstddef>
16#include <array>
17#include <tuple>
18#include <type_traits>
19#include <chrono>
20#include <thread>
21
22namespace DeterministicConcurrency{
23
28 template<size_t N>
30
31 struct emplace_t {};
32
33 public:
34
36 template <typename... Tuples>
37 UserControlledScheduler(Tuples&&... tuples)
38 : UserControlledScheduler{std::index_sequence_for<Tuples...>{},
39 static_cast<Tuples&&>(tuples)...} {}
40
53 template<thread_status_t S, typename... Args>
54 void waitUntilAllThreadStatus(Args&&... threadIndexes){
55 for(size_t numThreads = 0; numThreads != sizeof...(threadIndexes);){
56 std::this_thread::sleep_for(std::chrono::milliseconds(1));
57 numThreads = 0;
58 ([&]{
59 if (getThreadStatus(threadIndexes) == S)
60 numThreads++;
61 }(),...);
62 }
63 return;
64 }
65
78 template<typename BasicLockable>
79 static void waitUntilLocked(BasicLockable* lockable){
80 while (lockable->try_lock()){
81 lockable->unlock();
82 std::this_thread::sleep_for(std::chrono::milliseconds(1));
83 }
84 }
85
98 template<thread_status_t S, typename... Args>
99 size_t waitUntilOneThreadStatus(Args&&... threadIndexes){
100 size_t threadIndex = -1;
101 for (;threadIndex == -1;){
102 std::this_thread::sleep_for(std::chrono::milliseconds(1));
103 ([&]{
104 if (getThreadStatus(threadIndexes) == S)
105 threadIndex = threadIndexes;
106 }(),...);
107 }
108 return threadIndex;
109 }
110
122 template<typename... Args>
123 void switchContextTo(Args&&... threadIndexes){
124 ([&]{
125 proceed(threadIndexes);
126 wait(threadIndexes);
127 }(),...);
128 }
129
139 switchContextAll(std::make_index_sequence<N>());
140 }
141
152 template<typename... Args>
153 void joinOn(Args&&... threadIndexes){
154 static_assert(sizeof...(threadIndexes) <= N, "Too many args");
155 (_threads[threadIndexes].join(), ...);
156 }
157
166 void joinAll(){
167 for (auto& _thread : _threads)
168 _thread.join();
169 }
170
181 template<typename... Args>
182 void proceed(Args&&... threadIndexes){
183 static_assert(sizeof...(threadIndexes) <= N, "Too many args");
184 (_threads[threadIndexes].tick(), ...);
185 }
186
197 template<typename... Args>
198 void wait(Args&&... threadIndexes){
199 static_assert(sizeof...(threadIndexes) <= N, "Too many args");
200 (_threads[threadIndexes].wait_for_tock(), ...);
201 }
202
209 thread_status_t getThreadStatus(size_t threadIndex){
210 return _contexts[threadIndex].thread_status_v;
211 }
212
213 private:
214
215 template <typename... Tuples>
216 UserControlledScheduler(emplace_t, Tuples&&... tuples)
217 : _threads{std::make_from_tuple<DeterministicThread>(tuples)...} {}
218
219 template <typename... Tuples, std::size_t... Is>
220 UserControlledScheduler(std::index_sequence<Is...>, Tuples&&... tuples)
221 : UserControlledScheduler{
222 emplace_t{}, std::tuple_cat(std::tuple{&std::get<Is>(_contexts)},
223 static_cast<Tuples&&>(tuples))...} {}
224
225
226 template <std::size_t... Is>
227 void switchContextAll(std::index_sequence<Is...>){
228 ([&]{
229 proceed(Is);
230 wait(Is);
231 }(),...);
232 }
233
234 std::array<thread_context, N> _contexts;
235 std::array<DeterministicThread, N> _threads;
236 };
237
254 template<typename... Tuples>
255 auto make_UserControlledScheduler(Tuples&&... tuples) {
256 return UserControlledScheduler<sizeof...(Tuples)>(static_cast<Tuples&&>(tuples)...);
257 }
258
259}
thread_status_t
Enum describing the possible states of a thread.
Definition DeterministicThread.h:25
auto make_UserControlledScheduler(Tuples &&... tuples)
Helper function to create an UserControlledScheduler.
Definition UserControlledScheduler.h:255
A scheduler which allow to manage the flow of its managed threads.
Definition UserControlledScheduler.h:29
void joinOn(Args &&... threadIndexes)
Perform a join on the threads with threadIndexes.
Definition UserControlledScheduler.h:153
void proceed(Args &&... threadIndexes)
Allow threadIndexes to continue while not stopping the scheduler thread.
Definition UserControlledScheduler.h:182
void switchContextAll()
Switch context allowing all the threads to proceed while stopping the scheduler from executing until ...
Definition UserControlledScheduler.h:138
void wait(Args &&... threadIndexes)
Wait until the threads with threadIndexes go into WAITING status.
Definition UserControlledScheduler.h:198
void joinAll()
Perform a join on all threads.
Definition UserControlledScheduler.h:166
size_t waitUntilOneThreadStatus(Args &&... threadIndexes)
Wait until at least one of the threadIndexes threads have thread_status_v equal to S and return the i...
Definition UserControlledScheduler.h:99
thread_status_t getThreadStatus(size_t threadIndex)
Get the Thread Status of the thread with threadIndex.
Definition UserControlledScheduler.h:209
static void waitUntilLocked(BasicLockable *lockable)
Wait until lockable is owned.
Definition UserControlledScheduler.h:79
void switchContextTo(Args &&... threadIndexes)
Switch context allowing the threads with threadIndexes to proceed while stopping the scheduler from e...
Definition UserControlledScheduler.h:123
void waitUntilAllThreadStatus(Args &&... threadIndexes)
Wait until all of the threadIndexes threads have thread_status_v equal to S.
Definition UserControlledScheduler.h:54