fairness  v1.0.0
A collection of advanced syncronization mechanisms.
Loading...
Searching...
No Matches
slim_priority_mutex.hpp
Go to the documentation of this file.
1
14#ifndef BOOST_FAIRNESS_SLIM_PRIORITY_MUTEX_HPP
15#define BOOST_FAIRNESS_SLIM_PRIORITY_MUTEX_HPP
16#include <atomic>
17#include <cstring>
18#include <array>
22
23namespace boost::fairness{
24
30 template<bool> struct Range;
37 template<size_t N = 1, typename = Range<true> >
38 struct slim_priority_mutex{};
39
58 template<size_t N>
59 class slim_priority_mutex<N, Range<(1 <= N && N <= BOOST_FAIRNESS_SPM64B_SUPPORTED_PRIORITIES)>>{
60
61 using Thread_cnt_t = uint32_t;
62
63 public:
64
66 slim_priority_mutex() = default;
67
69 slim_priority_mutex(const slim_priority_mutex&) = delete;
70
72 slim_priority_mutex& operator=(const slim_priority_mutex&) = delete;
73
75 slim_priority_mutex(slim_priority_mutex&&) = delete;
76
78 slim_priority_mutex& operator=(slim_priority_mutex&&) = delete;
79
81 ~slim_priority_mutex() = default;
82
120 void lock(Priority_t const priority = 0){
121
122 control_block_64b_t localCtrl = ctrl_.load();
123
124 // try to increment the waiters counter in this priority
125 for(;;){
126 // if we risk an overflow lets spin instead
127 if (localCtrl.priority_[priority] == uint8_t(-1)){
128 localCtrl = ctrl_.load();
129 continue;
130 }
131 if (ctrl_.compare_exchange_weak(localCtrl, localCtrl.increasePriority(priority))){
132 break;
133 }
134 }
135 // if we can proceed we do and decrement the counter otherwise we wait on an atomic_flag
136 for(;;){
137 localCtrl = ctrl_.load();
138 if (!localCtrl.isOwned_() && priority <= localCtrl.owned_ && ctrl_.compare_exchange_strong(localCtrl, localCtrl.setOwned())){
139 break;
140 }
141 waitingFlags_[priority].wait(false);
142 }
143
144 localCtrl = ctrl_.load();
145
146 for(;;){
147 if (ctrl_.compare_exchange_weak(localCtrl, localCtrl.decreasePriority(priority))){
148 break;
149 }
150 }
151
152 }
153
191 void unlock(){
192 Priority_t localFirstPriority;
193 control_block_64b_t localCtrl;
194 for (;;){
195 reset_();
196 localCtrl = ctrl_.load();
197 localFirstPriority = find_first_priority_(localCtrl);
198 if (localFirstPriority < N){
199 waitingFlags_[localFirstPriority].test_and_set();
200 waitingFlags_[localFirstPriority].notify_one();
201 }
202 if (ctrl_.compare_exchange_weak(localCtrl, localCtrl.setPriority(localFirstPriority)))
203 break;
204 }
205 }
206
248 [[nodiscard]] bool try_lock(Priority_t const priority = 0){
249 control_block_64b_t localCtrl = ctrl_.load();
250 return !localCtrl.isOwned_() && priority <= localCtrl.owned_ && ctrl_.compare_exchange_strong(localCtrl, localCtrl.setOwned());
251 }
252
253 private:
254 std::array<std::atomic_flag, N> waitingFlags_{};
255 std::atomic<control_block_64b_t> ctrl_;
256
257 void reset_(){ // there probably is a much better way to do this
258 std::memset(&waitingFlags_, 0b00000000, N); // maybe undefined because lock is reading on the waits? Should be ok.
259 }
260
261 Priority_t find_first_priority_(control_block_64b_t const& ctrl){
262 for (Priority_t i = 0; i < N; ++i){
263 if (ctrl.priority_[i] > 0)
264 return i;
265 }
267 }
268
269 };
270
271#ifdef BOOST_FAIRNESS_HAS_DWCAS
272
291 template<size_t N>
292 class slim_priority_mutex<N, Range<(BOOST_FAIRNESS_SPM64B_SUPPORTED_PRIORITIES < N && N <= BOOST_FAIRNESS_SPM128B_SUPPORTED_PRIORITIES)>>{
293
294 using Thread_cnt_t = uint32_t;
295
296 public:
297
299 slim_priority_mutex() = default;
300
302 slim_priority_mutex(const slim_priority_mutex&) = delete;
303
305 slim_priority_mutex& operator=(const slim_priority_mutex&) = delete;
306
308 slim_priority_mutex(slim_priority_mutex&&) = delete;
309
311 slim_priority_mutex& operator=(slim_priority_mutex&&) = delete;
312
314 ~slim_priority_mutex() = default;
315
353 void lock(Priority_t const priority = 0){
354
355 control_block_128b_t localCtrl = ctrl_.load();
356
357 // try to increment the waiters counter in this priority
358 for(;;){
359 // if we risk an overflow lets spin instead
360 if (localCtrl.priority_[priority] == uint8_t(-1)){
361 localCtrl = ctrl_.load();
362 continue;
363 }
364 if (ctrl_.compare_exchange_weak(localCtrl, localCtrl.increasePriority(priority))){
365 break;
366 }
367 }
368 // if we can proceed we do and decrement the counter otherwise we wait on an atomic_flag
369 for(;;){
370 localCtrl = ctrl_.load();
371 if (!localCtrl.isOwned_() && priority <= localCtrl.owned_ && ctrl_.compare_exchange_strong(localCtrl, localCtrl.setOwned())){
372 break;
373 }
374 waitingFlags_[priority].wait(false);
375 }
376
377 localCtrl = ctrl_.load();
378
379 for(;;){
380 if (ctrl_.compare_exchange_weak(localCtrl, localCtrl.decreasePriority(priority))){
381 break;
382 }
383 }
384
385 }
386
424 void unlock(){
425 Priority_t localFirstPriority;
426 control_block_128b_t localCtrl;
427 for (;;){
428 reset_();
429 localCtrl = ctrl_.load();
430 localFirstPriority = find_first_priority_(localCtrl);
431 if (localFirstPriority < N){
432 waitingFlags_[localFirstPriority].test_and_set();
433 waitingFlags_[localFirstPriority].notify_one();
434 }
435 if (ctrl_.compare_exchange_weak(localCtrl, localCtrl.setPriority(localFirstPriority)))
436 break;
437 }
438 }
439
481 [[nodiscard]] bool try_lock(Priority_t const priority = 0){
482 control_block_128b_t localCtrl = ctrl_.load();
483 return !localCtrl.isOwned_() && priority <= localCtrl.owned_ && ctrl_.compare_exchange_strong(localCtrl, localCtrl.setOwned());
484 }
485
486 private:
487 std::array<boost::atomic_flag, N> waitingFlags_{};
488 boost::atomic<control_block_128b_t> ctrl_;
489
490 void reset_(){ // there probably is a much better way to do this
491 std::memset(&waitingFlags_, 0b00000000, N); // maybe undefined because lock is reading on the waits? Should be ok.
492 }
493
494 Priority_t find_first_priority_(control_block_128b_t const& ctrl){
495 for (Priority_t i = 0; i < N; ++i){
496 if (ctrl.priority_[i] > 0)
497 return i;
498 }
499 return BOOST_FAIRNESS_SPM128B_SUPPORTED_PRIORITIES;
500 }
501
502 };
503
504#endif // BOOST_FAIRNESS_HAS_DWCAS
505
506}
507#endif // BOOST_FAIRNESS_SLIM_PRIORITY_MUTEX_HPP
void lock(Priority_t const priority=0)
Lock the slim_priority_mutex. If another thread has already locked the mutex or other threads are wai...
Definition slim_priority_mutex.hpp:120
bool try_lock(Priority_t const priority=0)
Try to acquire the unique ownership of the slim_priority_mutex. Returns immediately....
Definition slim_priority_mutex.hpp:248
void unlock()
Unlocks the mutex. The mutex must be locked by the current thread of execution, otherwise,...
Definition slim_priority_mutex.hpp:191
This file contains configurations about boost and 128bit cpu support. TODO.
This file contains the definition of the control_block_t. TODO.
#define BOOST_FAIRNESS_SPM64B_SUPPORTED_PRIORITIES
Definition control_block_t.hpp:134
Definition acquisition_modes.hpp:16
uint8_t Priority_t
Definition priority_t.hpp:17
Alias the type Priority_t. Priority_t is the type of priorities that are used by the priority_mutexes...