General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

112 lines
3.1 KiB

#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;
}
};
}