2017-04-17 01:22:59 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
// A object which can be stored and taken from atomically.
|
|
|
|
template <class T>
|
|
|
|
struct AtomicObject {
|
|
|
|
void Set(std::unique_ptr<T> t) {
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
value_ = std::move(t);
|
|
|
|
cv_.notify_one();
|
|
|
|
}
|
|
|
|
|
2017-07-16 00:08:07 +00:00
|
|
|
void SetIfEmpty(std::unique_ptr<T> t) {
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
if (value_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
value_ = std::move(t);
|
|
|
|
cv_.notify_one();
|
|
|
|
}
|
|
|
|
|
2017-04-17 01:22:59 +00:00
|
|
|
std::unique_ptr<T> Take() {
|
|
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
|
|
|
while (!value_) {
|
|
|
|
// release lock as long as the wait and reaquire it afterwards.
|
|
|
|
cv_.wait(lock);
|
|
|
|
}
|
2017-04-22 07:42:57 +00:00
|
|
|
|
2017-04-17 01:22:59 +00:00
|
|
|
return std::move(value_);
|
|
|
|
}
|
|
|
|
|
2017-09-22 02:25:33 +00:00
|
|
|
template <typename TAction>
|
|
|
|
void WithLock(TAction action) {
|
|
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
|
|
|
bool had_value = !!value_;
|
|
|
|
action(value_);
|
|
|
|
bool has_value = !!value_;
|
|
|
|
|
|
|
|
if (had_value != has_value)
|
|
|
|
cv_.notify_one();
|
|
|
|
}
|
|
|
|
|
2017-04-17 01:22:59 +00:00
|
|
|
private:
|
|
|
|
std::unique_ptr<T> value_;
|
|
|
|
mutable std::mutex mutex_;
|
|
|
|
std::condition_variable cv_;
|
|
|
|
};
|