Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
sync_primitives.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11#pragma once
12
13#include <mutex>
14#include <condition_variable>
15#include <atomic>
16#include <chrono>
17#include <memory>
18
19namespace kcenon::thread::sync {
26 template<typename Mutex>
27 class scoped_lock_guard {
28 public:
33 explicit scoped_lock_guard(Mutex& mutex)
34 : mutex_(mutex), locked_(true) {
35 mutex_.lock();
36 }
37
43 template<typename Rep, typename Period>
44 scoped_lock_guard(Mutex& mutex, const std::chrono::duration<Rep, Period>& timeout)
45 : mutex_(mutex), locked_(false) {
46 if constexpr (std::is_same_v<Mutex, std::timed_mutex> ||
47 std::is_same_v<Mutex, std::recursive_timed_mutex>) {
48 locked_ = mutex_.try_lock_for(timeout);
49 } else {
50 // Fallback for mutexes without timeout support
51 locked_ = mutex_.try_lock();
52 }
53 }
54
59 if (locked_) {
60 mutex_.unlock();
61 }
62 }
63
64 // Non-copyable and non-movable
69
74 [[nodiscard]] bool owns_lock() const noexcept {
75 return locked_;
76 }
77
81 void unlock() {
82 if (locked_) {
83 mutex_.unlock();
84 locked_ = false;
85 }
86 }
87
88 private:
89 Mutex& mutex_;
90 bool locked_;
91 };
92
97 public:
100
101 // Non-copyable but movable
106
111 template<typename Lock>
112 void wait(Lock& lock) {
113 cv_.wait(lock);
114 }
115
121 template<typename Lock, typename Predicate>
122 void wait(Lock& lock, Predicate predicate) {
123 cv_.wait(lock, predicate);
124 }
125
132 template<typename Lock, typename Rep, typename Period>
133 bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& timeout) {
134 return cv_.wait_for(lock, timeout) == std::cv_status::no_timeout;
135 }
136
144 template<typename Lock, typename Rep, typename Period, typename Predicate>
145 bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& timeout, Predicate predicate) {
146 return cv_.wait_for(lock, timeout, predicate);
147 }
148
152 void notify_one() noexcept {
153 cv_.notify_one();
154 }
155
159 void notify_all() noexcept {
160 cv_.notify_all();
161 }
162
163 private:
164 std::condition_variable cv_;
165 };
166
171 public:
172 atomic_flag_wrapper() noexcept : flag_(ATOMIC_FLAG_INIT) {}
174
175 // Non-copyable but movable
180
186 bool test_and_set(std::memory_order order = std::memory_order_acq_rel) noexcept {
187 return flag_.test_and_set(order);
188 }
189
194 void clear(std::memory_order order = std::memory_order_release) noexcept {
195 flag_.clear(order);
196 }
197
203 bool test(std::memory_order order = std::memory_order_acquire) const noexcept {
204 return flag_.test(order);
205 }
206
211 void wait(bool expected, std::memory_order order = std::memory_order_acquire) const noexcept {
212 flag_.wait(expected, order);
213 }
214
218 void notify_one() noexcept {
219 flag_.notify_one();
220 }
221
225 void notify_all() noexcept {
226 flag_.notify_all();
227 }
228
229 private:
230 std::atomic_flag flag_;
231 };
232
237 public:
240
241 // Non-copyable and non-movable
246
250 void lock() {
251 mutex_.lock();
252 }
253
258 bool try_lock() {
259 return mutex_.try_lock();
260 }
261
265 void unlock() {
266 mutex_.unlock();
267 }
268
272 void lock_shared() {
273 mutex_.lock_shared();
274 }
275
281 return mutex_.try_lock_shared();
282 }
283
288 mutex_.unlock_shared();
289 }
290
291 private:
292 std::shared_mutex mutex_;
293 };
294
295 // Convenience type aliases
296 using unique_lock = std::unique_lock<std::mutex>;
297 using shared_lock = std::shared_lock<shared_mutex_wrapper>;
298 using scoped_mutex_lock = scoped_lock_guard<std::mutex>;
299 using scoped_shared_mutex_lock = scoped_lock_guard<shared_mutex_wrapper>;
300}
Enhanced atomic flag with additional operations.
atomic_flag_wrapper & operator=(atomic_flag_wrapper &&)=default
atomic_flag_wrapper(atomic_flag_wrapper &&)=default
void notify_one() noexcept
Notify one thread waiting on this flag.
void wait(bool expected, std::memory_order order=std::memory_order_acquire) const noexcept
Wait until the flag becomes false.
bool test(std::memory_order order=std::memory_order_acquire) const noexcept
Test the flag without modifying it.
void clear(std::memory_order order=std::memory_order_release) noexcept
Clear the flag atomically.
atomic_flag_wrapper(const atomic_flag_wrapper &)=delete
bool test_and_set(std::memory_order order=std::memory_order_acq_rel) noexcept
Test and set the flag atomically.
atomic_flag_wrapper & operator=(const atomic_flag_wrapper &)=delete
void notify_all() noexcept
Notify all threads waiting on this flag.
Enhanced condition variable wrapper with timeout and predicate support.
bool wait_for(Lock &lock, const std::chrono::duration< Rep, Period > &timeout)
Wait with timeout.
condition_variable_wrapper(const condition_variable_wrapper &)=delete
void wait(Lock &lock)
Wait indefinitely for notification.
void notify_one() noexcept
Notify one waiting thread.
void wait(Lock &lock, Predicate predicate)
Wait with predicate until condition is met.
bool wait_for(Lock &lock, const std::chrono::duration< Rep, Period > &timeout, Predicate predicate)
Wait with timeout and predicate.
condition_variable_wrapper(condition_variable_wrapper &&)=default
void notify_all() noexcept
Notify all waiting threads.
condition_variable_wrapper & operator=(const condition_variable_wrapper &)=delete
condition_variable_wrapper & operator=(condition_variable_wrapper &&)=default
RAII-based scoped lock guard with timeout support.
Definition forward.h:205
bool owns_lock() const noexcept
Check if the lock was successfully acquired.
void unlock()
Explicitly release the lock before destruction.
scoped_lock_guard(Mutex &mutex)
Construct and immediately acquire the lock.
scoped_lock_guard(scoped_lock_guard &&)=delete
scoped_lock_guard(const scoped_lock_guard &)=delete
scoped_lock_guard & operator=(const scoped_lock_guard &)=delete
~scoped_lock_guard()
Destructor - automatically releases the lock if held.
scoped_lock_guard(Mutex &mutex, const std::chrono::duration< Rep, Period > &timeout)
Construct and try to acquire the lock with timeout.
scoped_lock_guard & operator=(scoped_lock_guard &&)=delete
Shared mutex wrapper with reader-writer lock semantics.
void lock()
Acquire exclusive (writer) lock.
bool try_lock_shared()
Try to acquire shared (reader) lock.
void unlock()
Release exclusive (writer) lock.
void lock_shared()
Acquire shared (reader) lock.
shared_mutex_wrapper(const shared_mutex_wrapper &)=delete
shared_mutex_wrapper & operator=(shared_mutex_wrapper &&)=delete
shared_mutex_wrapper & operator=(const shared_mutex_wrapper &)=delete
shared_mutex_wrapper(shared_mutex_wrapper &&)=delete
bool try_lock()
Try to acquire exclusive (writer) lock.
void unlock_shared()
Release shared (reader) lock.
std::shared_lock< shared_mutex_wrapper > shared_lock
scoped_lock_guard< shared_mutex_wrapper > scoped_shared_mutex_lock
std::unique_lock< std::mutex > unique_lock
scoped_lock_guard< std::mutex > scoped_mutex_lock