header_utils
Loading...
Searching...
No Matches
threading.h
1
4
5#pragma once
6
7#include "min-cpp-version/cpp20.h"
8#include <mutex>
9#include <shared_mutex>
10#include <chrono>
11
12namespace ghassanpl
13{
17
19 template <typename T>
20 concept mutexlike = requires(T t)
21 {
22 { t.lock() };
23 { t.try_lock() } -> std::convertible_to<bool>;
24 { t.unlock() };
25 };
26
28 template <typename T>
29 concept timed_mutexlike = mutexlike<T> && requires(T t)
30 {
31 { t.try_lock_for(std::chrono::seconds(1)) } -> std::convertible_to<bool>;
32 { t.try_lock_until(std::chrono::high_resolution_clock::now()) } -> std::convertible_to<bool>;
33 };
34
36 template <typename T>
37 concept shared_mutexlike = mutexlike<T> && requires(T t)
38 {
39 { t.lock_shared() };
40 { t.try_lock_shared() } -> std::convertible_to<bool>;
41 { t.unlock_shared() };
42 };
43
45 template <mutexlike MUTEX_TYPE, typename FUNC, typename... ARGS>
46 auto under_protection(MUTEX_TYPE& m, FUNC&& func, ARGS&&... args)
47 {
48 std::unique_lock<MUTEX_TYPE> guard{ m };
49 if constexpr (std::is_invocable_v<FUNC, MUTEX_TYPE&, ARGS...>)
50 return func(m, std::forward<ARGS>(args)...);
51 else
52 return func(std::forward<ARGS>(args)...);
53 }
54
56 template <shared_mutexlike MUTEX_TYPE, typename FUNC, typename... ARGS>
57 auto under_read_protection(MUTEX_TYPE& m, FUNC&& func, ARGS&&... args)
58 {
59 std::shared_lock<MUTEX_TYPE> guard{ m };
60 if constexpr (std::is_invocable_v<FUNC, MUTEX_TYPE&, ARGS...>)
61 return func(m, std::forward<ARGS>(args)...);
62 else
63 return func(std::forward<ARGS>(args)...);
64 }
65
67 template <mutexlike MUTEX_TYPE, typename T>
68 [[nodiscard]] auto protected_copy(MUTEX_TYPE& m, T&& t)
69 {
70 using lock_type = std::conditional_t<shared_mutexlike<MUTEX_TYPE>, std::shared_lock<MUTEX_TYPE>, std::unique_lock<MUTEX_TYPE>>;
71 lock_type guard{ m };
72 return t;
73 }
74
76 template <mutexlike MUTEX_TYPE, typename T>
77 [[nodiscard]] auto protected_move(MUTEX_TYPE& m, T&& t)
78 {
79 std::unique_lock guard{ m };
80 return std::move(t);
81 }
82
84 template <mutexlike MUTEX_TYPE, typename T, typename U>
85 [[nodiscard]] auto protected_exchange(MUTEX_TYPE& m, T& t, U&& u) -> T
86 {
87 std::unique_lock guard{ m };
88 return std::exchange<T>(t, std::forward<U>(u));
89 }
90
92 template <typename T, mutexlike MUTEX_TYPE = std::mutex>
94 {
95 // TODO: Timed versions of this class's functions
96 // TODO: std::optional<T> try_get_for(...);
97
98 using object_type = T;
99 using reference = object_type&;
100 using const_reference = object_type const&;
101 using mutex_type = MUTEX_TYPE;
102 static constexpr bool is_shared = shared_mutexlike<mutex_type>;
103 static constexpr bool is_timed = timed_mutexlike<mutex_type>;
104
106 T get() const
107 {
108 return protected_copy(m_mutex, m_value);
109 }
110
113 {
114 return protected_move(m_mutex, m_value);
115 }
116
118 template <typename U>
119 T exchange(U&& u)
120 {
121 return protected_exchange(m_mutex, m_value, std::forward<U>(u));
122 }
123
125 template <typename FUNC>
126 requires is_shared
127 auto read_only_access(FUNC&& func) const
128 {
129 static_assert(std::is_invocable_v<FUNC, const_reference>, "Function must be invocable with a const reference to the object");
130 return under_read_protection(m_mutex, func, m_value);
131 }
132
134 template <typename U = T>
135 void set(U&& value)
136 {
137 under_protection(m_mutex, [&]() { m_value = std::forward<U>(value); });
138 }
139
141 template <typename FUNC>
142 auto mutate_in_place(FUNC&& func)
143 {
144 static_assert(std::is_invocable_v<FUNC, reference>, "Function must be invocable with a reference to the object");
145 return under_protection(m_mutex, func, m_value);
146 }
147
150 template <typename FUNC>
151 void mutate_by_copy(FUNC&& func)
152 {
153 static_assert(std::is_invocable_v<FUNC, reference>, "Function must be invocable with a reference to the object");
154 auto copy = this->get();
155 func(copy);
156 this->set(std::move(copy));
157 }
158
159 mutex_type const& mutex() const { return m_mutex; }
160
161 protected:
162
163 T m_value;
164 mutable mutex_type m_mutex;
165 };
166
168 template <typename T, shared_mutexlike MUTEX_TYPE = std::shared_mutex>
170
172}
Anything that's lockable.
Definition threading.h:20
RW mutex (read access can be shared, write access is exclusive).
Definition threading.h:37
Any mutexlike that can also be attempted to be locked for some time.
Definition threading.h:29
protected_object< T, MUTEX_TYPE > shared_protected_object
Same as protected_object but uses std::shared_mutex by default.
Definition threading.h:169
auto protected_move(MUTEX_TYPE &m, T &&t)
Moves t under the protection of mutexlike m.
Definition threading.h:77
auto protected_copy(MUTEX_TYPE &m, T &&t)
Creates a copy of t under the protection of mutexlike m.
Definition threading.h:68
auto under_read_protection(MUTEX_TYPE &m, FUNC &&func, ARGS &&... args)
Runs func under the read (shared) protection of mutexlike m.
Definition threading.h:57
auto protected_exchange(MUTEX_TYPE &m, T &t, U &&u) -> T
Exchanges t with u and returns the value of t, all under the protection of mutexlike m.
Definition threading.h:85
auto under_protection(MUTEX_TYPE &m, FUNC &&func, ARGS &&... args)
Runs func under the protection of mutexlike m.
Definition threading.h:46
Primary namespace for everything in this library.
Definition align+rec2.h:10
A class that stores an object to which access is protected via a mutexlike; all operations are thread...
Definition threading.h:94
void set(U &&value)
Sets a new value for the object.
Definition threading.h:135
T exchange(U &&u)
Exchanges the value of the object with u and returns the old value.
Definition threading.h:119
auto read_only_access(FUNC &&func) const
Calls func with a const reference to the object which can be safely accessed; only available if the m...
Definition threading.h:127
T take()
Takes the value of the object via move.
Definition threading.h:112
T get() const
Returns a copy of the object.
Definition threading.h:106
void mutate_by_copy(FUNC &&func)
Calls func with a reference to a copy of the object, but not under the protection of the mutex.
Definition threading.h:151
auto mutate_in_place(FUNC &&func)
Calls func with a reference to the object which can be safely mutated.
Definition threading.h:142