编辑:我已将此问题移至codereview 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_
会员吗?应用
我想开发这样的holder来将活动异常从工作线程传递给主线程。
主线程:
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
是线程安全的)因为
如果没有共享状态或共享状态已存储值或异常,则抛出异常。
答案 0 :(得分:0)
不,此代码不正确:T::~T()
可能会被多次调用。您可能应该使用shared_ptr
。
你对活动异常的意思是什么?在抛出异常并且如何之后,工作线程是否继续执行?
我的意思是
std::promise
对于此目的来说似乎并不太糟糕。 那么,如何在工作线程中重新设置另一个异常以及为什么呢?