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>
|
2019-10-13 21:00:20 +08:00
|
|
|
#include <utility>
|
2019-09-15 04:41:56 +08:00
|
|
|
|
|
|
|
|
|
|
|
namespace sgnl {
|
|
|
|
|
|
|
|
|
2019-10-13 21:00:20 +08:00
|
|
|
/// 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:
|
2019-10-13 21:00:20 +08:00
|
|
|
explicit AtomicCondition(ValueType initial_value)
|
|
|
|
: value_(initial_value)
|
2019-09-23 18:04:28 +08:00
|
|
|
, 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
|
|
|
{
|
2019-10-13 21:00:20 +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
|
|
|
}
|
|
|
|
|
2020-07-17 22:50:51 +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();
|
|
|
|
}
|
|
|
|
|
2019-10-13 21:00:20 +08:00
|
|
|
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
|
|
|
|
2019-10-13 21:00:20 +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
|
|
|
}
|
|
|
|
|
2019-10-13 21:00:20 +08:00
|
|
|
template<typename... Args>
|
|
|
|
auto wait_for(Args&&... args) const
|
2019-09-17 00:07:58 +08:00
|
|
|
{
|
2019-10-13 21:00:20 +08:00
|
|
|
std::unique_lock lock(this->mutex_);
|
|
|
|
return this->condvar_.wait_for(lock, std::forward<Args>(args)...);
|
|
|
|
}
|
2019-09-17 00:07:58 +08:00
|
|
|
|
2019-10-13 21:00:20 +08:00
|
|
|
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)...);
|
2019-09-17 00:07:58 +08:00
|
|
|
}
|
|
|
|
|
2019-09-15 04:41:56 +08:00
|
|
|
private:
|
|
|
|
std::atomic<ValueType> value_;
|
2019-09-23 18:04:28 +08:00
|
|
|
mutable std::mutex mutex_;
|
2019-09-15 04:41:56 +08:00
|
|
|
mutable std::condition_variable condvar_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace sgnl
|
|
|
|
|