#pragma once
|
|
|
|
#include <atomic>
|
|
#include <concepts>
|
|
|
|
#include "gp_config.hpp"
|
|
|
|
namespace gp {
|
|
/**
|
|
* @brief CADR lock_guard for generic locking mechanisms
|
|
*
|
|
* @tparam T
|
|
*/
|
|
template<typename T>
|
|
class lock_guard {
|
|
T& ref;
|
|
public:
|
|
lock_guard(T& _ref)
|
|
: ref(_ref)
|
|
{
|
|
ref.lock();
|
|
}
|
|
|
|
~lock_guard() {
|
|
ref.unlock();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A fast mutual exclusion handler WITHOUT deadlock detection
|
|
*/
|
|
class fast_bottleneck {
|
|
std::atomic_bool flag;
|
|
public:
|
|
fast_bottleneck() = default;
|
|
fast_bottleneck(fast_bottleneck&) = delete;
|
|
fast_bottleneck(fast_bottleneck&&) = delete;
|
|
|
|
void lock() {
|
|
while(not try_lock());
|
|
}
|
|
|
|
[[nodiscard]] bool try_lock() {
|
|
bool f = false;
|
|
bool t = true;
|
|
return flag.compare_exchange_strong(f,t,std::memory_order::acquire);
|
|
}
|
|
|
|
void unlock() {
|
|
gp_config::assertion(try_unlock(), "Unlocking failed in fast_bottleneck: potential double unlocking issue");
|
|
}
|
|
|
|
[[nodiscard]] bool try_unlock() {
|
|
bool f = false;
|
|
bool t = true;
|
|
return flag.compare_exchange_strong(t,f,std::memory_order::release);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A fast semaphore exclusion handler WITHOUT deadlock detection
|
|
*/
|
|
template<std::integral T, T default_increment, T maximum_increment>
|
|
class fast_semaphore {
|
|
std::atomic<T> flag;
|
|
public:
|
|
fast_semaphore() = default;
|
|
fast_semaphore(fast_semaphore&) = delete;
|
|
fast_semaphore(fast_semaphore&&) = delete;
|
|
|
|
enum class tristate {
|
|
success,
|
|
timing,
|
|
error
|
|
};
|
|
|
|
void lock_super() {
|
|
auto value = flag.fetch_add(maximum_increment, std::memory_order::relaxed);
|
|
while(value > maximum_increment) { value = flag.load(std::memory_order::release); }
|
|
}
|
|
|
|
|
|
template<T increment = default_increment>
|
|
void lock() {
|
|
while(not try_lock<increment>());
|
|
}
|
|
|
|
template<T increment = default_increment>
|
|
[[nodiscard]] bool try_lock() {
|
|
T expect = flag.load(std::memory_order::relaxed);
|
|
T target = expect + increment;
|
|
if(target > maximum_increment) return false;
|
|
return flag.compare_exchange_strong(expect,target,std::memory_order::acquire);
|
|
}
|
|
|
|
template<T increment = default_increment>
|
|
void unlock() {
|
|
tristate v;
|
|
do{ v = try_unlock<increment>(); }
|
|
while(v == tristate::timing);
|
|
gp_config::assertion(v == tristate::success, "Over unlocking may have happened");
|
|
}
|
|
|
|
template<T increment = default_increment>
|
|
[[nodiscard]] tristate try_unlock() {
|
|
T expect = flag.load(std::memory_order::relaxed);
|
|
T target = expect - increment;
|
|
if(target < 0) return tristate::error;
|
|
return flag.compare_exchange_strong(expect,target,std::memory_order::release) ? tristate::success : tristate::timing;
|
|
}
|
|
};
|
|
}
|