是否在`std :: tuple`上使用`std :: get< I>`保证对不同的`I`值是线程安全的? [英] Is using `std::get<I>` on a `std::tuple` guaranteed to be thread-safe for different values of `I`?
问题描述
假设我有
std::tuple<T0, T1, T2> my_tuple{x0, x1, x2};
其中T0
,T1
和T2
是值类型(即,不能使用别名).
只要每个线程都访问一个不同的元素,访问my_tuple
的元素并使用std::get
从多个线程中同时对其进行变异是否安全?
Is it safe to access my_tuple
's elements and mutate them concurrently from multiple threads using std::get
, as long as every thread accesses a different element?
示例:
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; };
...,但是它是由标准保证的吗?
Instinctively I would say it is safe, as my_tuple
can be thought of as struct { T0 x0; T1 x1; T2 x2; };
... but is it guaranteed by the standard?
推荐答案
由于std::get
在规范中没有关于其数据竞争属性的明确声明,因此我们使用[res.on.data]中定义的默认行为.种族].具体来说,第2段和第3段讲述了这个故事:
Since std::get
has no explicit statements in the specification about its data race properties, we fall back to the default behavior defined in [res.on.data.races]. Specifically, paragraphs 2 and 3 tell the story:
除非通过函数的参数直接或间接访问对象,否则C ++标准库函数不得直接或间接访问当前线程以外的线程可以访问的对象(1.10), 包括
this
.
A C++ standard library function shall not directly or indirectly access objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s arguments, including
this
.
AC ++标准库函数不得直接或间接修改可由当前线程以外的线程访问的对象(1.10),除非通过函数的非const
参数(包括this
)直接或间接访问对象.
A C ++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const
arguments, including this
.
这些仅针对与函数参数提供的对象不同的用途提供数据竞争保护.模板参数从技术上讲不是函数的参数,因此不符合条件.
These provide protection from data races only for uses that are not the same object provided by a function's arguments. A template parameter is not technically a function's arguments, so it doesn't qualify.
您的情况涉及多个线程将同一对象传递给不同的get
调用.由于您传递的是非const
参数,因此将假定get
正在修改其tuple
参数.因此,在同一对象上调用get
相当于从多个线程修改该对象.因此,调用它可以合法地引发tuple
上的数据竞赛.
Your case involves multiple threads passing the same object to different get
calls. Since you are passing a non-const
parameter, get
will be assumed to be modifying its tuple
argument. Therefore, calling get
on the same object counts as modifying the object from multiple threads. And therefore, calling it can legally provoke a data race on the tuple
.
即使从技术上讲,它只是从tuple
中提取一个子对象,因此不应干扰该对象本身或其其他子对象.标准不知道这一点.
Even though, technically speaking, it's just extracting a subobject from the tuple
and therefore should not disturb the object itself or its other subobjects. The standard does not know this.
但是,如果参数为const
,则不会认为get
与其他调用get
的const
引发数据竞争.这些只是从多个线程查看同一对象,这在标准库中是允许的.使用get
的非const
用途或使用tuple
对象的其他非const
用途,将引发数据争用.但是const
不能使用它.
However, if the parameter were const
, then get
would not be considered to provoke a data race with other const
calls to get
. These would simply be viewing the same object from multiple threads, which is allowed in the standard library. It would provoke a data race with non-const
uses of get
or with other non-const
uses of the tuple
object. But not with const
uses of it.
因此您可以访问"它们,但不能"修改".
So you can "access" them, but not "modify" them.
这篇关于是否在`std :: tuple`上使用`std :: get< I>`保证对不同的`I`值是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!