是否在`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`?

查看:83
本文介绍了是否在`std :: tuple`上使用`std :: get< I>`保证对不同的`I`值是线程安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有

std::tuple<T0, T1, T2> my_tuple{x0, x1, x2};

其中T0T1T2是值类型(即,不能使用别名).

只要每个线程都访问一个不同的元素,访问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与其他调用getconst引发数据竞争.这些只是从多个线程查看同一对象,这在标准库中是允许的.使用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&lt; I&gt;`保证对不同的`I`值是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆