编辑:我搬到这个问题代码审查https://codereview.stackexchange.com/questions/105742/thread-safe-holder线程安全的持有人
我实现了一个线程安全的持有人在线程之间安全地传递数据。
用户可以多次设置值,但只有第一个SetIfEmpty
调用存储该值,则用户可以多次读取该值。
template <typename T>
class ThreadSafeHolder {
public:
ThreadSafeHolder() : is_value_set_(false) {
}
void SetIfEmpty(const T& value) {
std::lock_guard<std::mutex> lock(mutex_);
// memory_order_relaxed is enough because storing to
// `is_value_set_` happens only in `SetIfEmpty` methods
// which are protected by mutex.
if (!is_value_set_.load(std::memory_order_relaxed)) {
new(GetPtr()) T(value);
is_value_set_.store(true, std::memory_order_release);
}
}
void SetIfEmpty(T&& value) {
std::lock_guard<std::mutex> lock(mutex_);
if (!is_value_set_.load(std::memory_order_relaxed)) {
new(GetPtr()) T(std::move(value));
is_value_set_.store(true, std::memory_order_release);
}
}
//! This method might be safely call only if previous `IsEmpty()`
//! call returned `false`.
const T& Get() const {
assert(!IsEmpty());
return *GetPtr();
}
bool IsEmpty() const {
// memory_order_acquire loading to become synchronize with
// memory_order_release storing in `SetIfEmpty` methods.
return !is_value_set_.load(std::memory_order_acquire);
}
~ThreadSafeHolder() {
if (!IsEmpty()) {
GetPtr()->~T();
}
}
private:
T* GetPtr() {
return reinterpret_cast<T*>(value_place_holder_);
}
const T* GetPtr() const {
return reinterpret_cast<const T*>(value_place_holder_);
}
// Reserved place for user data.
char value_place_holder_[sizeof(T)];
// Mutex for protecting writing access to placeholder.
std::mutex mutex_;
// Boolean indicator whether value was set or not.
std::atomic<bool> is_value_set_;
};
问题
- 是代码一般正确的吗?
- 访问
is_value_set_
成员是否正确同步? - 可能访问
is_value_set_
会员更轻松?
应用
我想开发这种支架从工作线程活跃异常传递到主线程。
主线程:
ThreadSafeHolder<std::exception_ptr> exceptionPtrHolder;
// Run many workers.
// Join workers.
if (!exceptionPtrHolder.IsEmpty()) {
std::rethrow_exception(exceptionPtrHolder.Get());
}
工作线程:
try {
while (exceptionPtrHolder.IsEmpty()) {
// Do hard work...
}
} catch (...) {
exceptionPtrHolder.SetIfEmpty(std::current_exception());
}
备注std::promise
std::promise
不适合在这里(尽管std::promise::set_value
是线程安全的),因为
如果没有共享状态或共享状态已存储值或异常,则会引发异常。
您可能想要使用['std :: aligned_storage_t'](http://en.cppreference。com/w/cpp/types/aligned_storage)而不是你的char数组 –
melak47
另外,这个问题可能更适合https://codereview.stackexchange.com/ – melak47
哦,我不小心把它贴在这里,谢谢你指点我。 关于codereview的这个问题[https://codereview.stackexchange.com/questions/105742/thread-safe-holder](https://codereview.stackexchange.com/questions/105742/thread-safe-holder)。 – user2932661