【发布时间】:2017-04-12 06:11:13
【问题描述】:
假设我有
std::tuple<T0, T1, T2> my_tuple{x0, x1, x2};
其中T0、T1 和T2 是值类型(即不可能有别名)。
访问my_tuple的元素并使用std::get从多个线程同时改变它们是否安全,只要每个线程访问不同的元素?
例子:
template <typename T>
void process(T& x) { /* mutate `x` */ }
// ...
std::thread{[&]{ process(std::get<0>(my_tuple)); }}.detach();
std::thread{[&]{ process(std::get<1>(my_tuple)); }}.detach();
std::thread{[&]{ process(std::get<2>(my_tuple)); }}.detach();
本能地我会说它是安全的,因为my_tuple 可以被认为是struct { T0 x0; T1 x1; T2 x2; };...但它是由标准保证的吗?
【问题讨论】:
-
std::get是constexpr,所以可以认为它等同于直接访问,只要线程访问不同的元素,这就是线程安全的。 -
@SamVarshavchik 有一个通用规则,即在没有同步的情况下访问两个不同线程中的数据是未定义的行为;是什么阻止
std::get算作对整个std::tuple对象的访问?我不是说它是,我只是不相信标准提供了保证。 -
@Yakk 从多个线程读取是安全的(afaik),如果线程写入超过零,则为 UB。
getonmy_tuple不会修改my_tuple并且可以提出最终修改将对其进行分离子对象的论点。 -
@krzaq
std::get是“正在阅读”,因为它将其参数作为非const引用?我的意思是,它应该正在阅读,但标准是否同意?我们可能不得不依靠“标准库不会做不必要的事情”。但是举个例子,假设我们有一个包含两个空类的元组,并且元组被压缩了。现在我们有两个相同的位置对象以非const的方式使用。标准可以吗?我不确定。我认为它应该是,我不确定它是否是。 -
@W.F.我怀疑这里的标准是健全的,但我不知道。我只是想指出这里有一个真正的问题。对于容器,标准在需要同步方面是明确的(const 是相互线程安全的),甚至列出了就同步而言被“视为 const”的显式非 const 方法。元组没有;这可能意味着该标准的其他部分足以保证正常行为,或者它可能表明存在标准缺陷。 无论如何,在实践中使用是安全的;没有编译器愚蠢到可以打破这一点。
标签: c++ multithreading c++11 thread-safety stdtuple