This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
signal-wrangler/include/sgnl/AtomicCondition.h

127 lines
2.9 KiB
C
Raw Normal View History

2019-09-15 04:41:56 +08:00
// Author: Thomas Trapp - https://thomastrapp.com/
// License: MIT
#pragma once
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <utility>
2019-09-15 04:41:56 +08:00
namespace sgnl {
/// Paires a `std::condition_variable` with a `std::atomic<ValueType>`,
/// protected by a mutex.
/// The interface of `std::condition_variable` is preserved through "perfect
/// forwarding".
2019-09-15 04:41:56 +08:00
template<typename ValueType>
class AtomicCondition
{
public:
explicit AtomicCondition(ValueType initial_value)
: value_(initial_value)
, mutex_()
2019-09-15 04:41:56 +08:00
, condvar_()
{
}
2019-09-17 00:05:13 +08:00
ValueType get() const noexcept
2019-09-15 04:41:56 +08:00
{
return this->value_.load();
}
2019-09-17 00:05:13 +08:00
void set(ValueType val) noexcept
2019-09-15 04:41:56 +08:00
{
// This lock is required to avoid a data race between calls to
// `AtomicCondition::get` when called in `AtomicCondition::wait_*` through
// a predicate.
std::unique_lock lock(this->mutex_);
this->value_.store(val);
2019-09-15 04:41:56 +08:00
}
void set_and_notify_one(ValueType val) noexcept
{
this->set(std::move(val));
this->condvar_.notify_one();
}
void set_and_notify_all(ValueType val) noexcept
{
this->set(std::move(val));
this->condvar_.notify_all();
}
auto native_handle() { return this->condvar_.native_handle(); }
void notify_one() const noexcept { this->condvar_.notify_one(); }
void notify_all() const noexcept { this->condvar_.notify_all(); }
2019-09-15 04:41:56 +08:00
template<typename... Args>
auto wait(Args&&... args) const
{
std::unique_lock lock(this->mutex_);
return this->condvar_.wait(lock, std::forward<Args>(args)...);
2019-09-15 04:41:56 +08:00
}
template<typename... Args>
auto wait_value(ValueType value, Args&&... args) const
{
std::unique_lock lock(this->mutex_);
return this->condvar_.wait(
lock,
std::forward<Args>(args)...,
[this, &value](){
return this->value_.load() == value;
});
}
template<typename... Args>
auto wait_for(Args&&... args) const
{
std::unique_lock lock(this->mutex_);
return this->condvar_.wait_for(lock, std::forward<Args>(args)...);
}
template<typename... Args>
auto wait_for_value(ValueType value, Args&&... args) const
{
std::unique_lock lock(this->mutex_);
return this->condvar_.wait_for(
lock,
std::forward<Args>(args)...,
[this, &value](){
return this->value_.load() == value;
});
}
template<typename... Args>
auto wait_until(Args&&... args) const
{
std::unique_lock lock(this->mutex_);
return this->condvar_.wait_until(lock, std::forward<Args>(args)...);
}
template<typename... Args>
auto wait_until_value(ValueType value, Args&&... args) const
{
std::unique_lock lock(this->mutex_);
return this->condvar_.wait_until(
lock,
std::forward<Args>(args)...,
[this, &value](){
return this->value_.load() == value;
});
}
2019-09-15 04:41:56 +08:00
private:
std::atomic<ValueType> value_;
mutable std::mutex mutex_;
2019-09-15 04:41:56 +08:00
mutable std::condition_variable condvar_;
};
} // namespace sgnl