ML Reference
mlTaskSystem.h
Go to the documentation of this file.
1/*************************************************************************************
2**
3** Copyright 2022, MeVis Medical Solutions AG
4**
5** The user may use this file in accordance with the license agreement provided with
6** the Software or, alternatively, in accordance with the terms contained in a
7** written agreement between the user and MeVis Medical Solutions AG.
8**
9** For further information use the contact form at https://www.mevislab.de/contact
10**
11**************************************************************************************/
12
13#pragma once
14
15#include "mlUtilsSystem.h"
16
17#include <stlab/concurrency/task.hpp>
18#include <stlab/concurrency/future.hpp>
19#include <stlab/concurrency/immediate_executor.hpp>
20#include <stlab/concurrency/await.hpp>
21
22ML_START_NAMESPACE
23
24void ML_UTILS_EXPORT execute_low(stlab::task<void()> f);
25void ML_UTILS_EXPORT execute_default(stlab::task<void()> f);
26void ML_UTILS_EXPORT execute_high(stlab::task<void()> f);
27
28namespace detail
29{
30 template <void (*Execute)(stlab::task<void()>)>
31 struct executor
32 {
33 void operator()(stlab::task<void()> f) const
34 {
35 Execute(std::move(f));
36 }
37 };
38
39#if STLAB_TASK_SYSTEM(PORTABLE)
40 ML_UTILS_EXPORT stlab::detail::priority_task_system& pts();
41#endif
42}
43
44/*
45 * These type definitions provide an interface to the stlab's
46 * TaskSystem. Use only instances of these types to access
47 * it.
48 *
49 * Never use the stlab::default_executor directly because
50 * that would instantiate in each shared library and in main
51 * a separate instance of the TaskSystem. This is against the
52 * principles that there should only be one task system per
53 * application and destruction of the TaskSystem while closing
54 * the applications does not work as intended.
55 */
59
60/*
61 * This function must be called just before the end of
62 * int main(). It ensures that all remaining tasks which
63 * are still in the queue of the TaskSystem will not executed
64 * any more and that the TaskSystem is shutdown in a controlled
65 * manner.
66 */
68
69
70namespace taskSystem
71{
72 /*
73 * This is a copy of stlab::await, which ensures that always the same instance of the
74 * priority_task_system singleton is returned (via detail::pts()), regardless of the compilation unit.
75 * See https://github.com/stlab/libraries/issues/519
76 */
77 template <typename T>
78 T await(stlab::future<T> x) {
79 if (auto result = x.get_try())
80 return stlab::detail::_get_optional<decltype(result)>{}(std::move(result)); // if ready, done
81
82 std::mutex m;
83 std::condition_variable condition;
84 bool flag{false};
85
86 auto hold = std::move(x).recover(stlab::immediate_executor, [&](auto&& r) {
87 x = std::forward<decltype(r)>(r);
88 {
89 std::unique_lock<std::mutex> lock{m};
90 flag = true;
91 condition.notify_one(); // must notify under lock
92 }
93 });
94
95 #if STLAB_TASK_SYSTEM(PORTABLE)
96 if (!detail::pts().wake()) detail::pts().add_thread();
97
98 /*
99 If no tasks are available we wait for one tick of the system clock and exponentially
100 back off on the wait as long as no tasks are available.
101 */
102
103 for (auto backoff{std::chrono::steady_clock::duration{std::chrono::milliseconds{1}}}; true;
104 backoff *= 2) {
105 {
106 std::unique_lock<std::mutex> lock{m};
107 if (condition.wait_for(lock, backoff, [&] { return flag; })) {
108 break;
109 }
110 }
111 detail::pts().wake(); // try to wake something to unstick.
112 }
113
114 #else
115
116 {
117 std::unique_lock<std::mutex> lock{m};
118 condition.wait(lock, [&] { return flag; });
119 }
120
121 #endif
122
123 return stlab::detail::_get_ready_future<T>{}(std::move(x));
124 }
125}
126
127ML_END_NAMESPACE
#define ML_UTILS_EXPORT
Defines platform dependent DLL export macro for mlUtils.
Definition mlUtilities.h:20
T await(stlab::future< T > x)
void ML_UTILS_EXPORT execute_high(stlab::task< void()> f)
void ML_UTILS_EXPORT execute_low(stlab::task< void()> f)
void ML_UTILS_EXPORT pre_exit()
void ML_UTILS_EXPORT execute_default(stlab::task< void()> f)
void operator()(stlab::task< void()> f) const