在'std :: tuple`上使用`std :: get <i>`保证对`I`的不同值是线程安全的?

时间:2016-11-28 13:40:08

标签: c++ multithreading c++11 thread-safety stdtuple

我们说我有

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

其中T0T1T2是值类型(即没有可能的别名)

访问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; }; ......但它是否由标准保证?

2 个答案:

答案 0 :(得分:8)

由于std::get在规范中没有关于其数据争用属性的明确语句,我们回到[res.on.data.races]中定义的默认行为。具体而言,第2和第3段讲述了这个故事:

  

C ++标准库函数不应直接或间接访问除当前线程以外的线程可访问的对象(1.10),除非通过函数的参数直接或间接访问对象,   包括this

     

AC ++标准库函数不应直接或间接修改除当前线程以外的线程可访问的对象(1.10),除非通过函数的非const参数直接或间接访问对象,包括{{ 1}}。

这些仅为与函数参数提供的对象不同的用户提供数据争用保护。模板参数在技术上不是函数的参数,因此它不符合条件。

您的案例涉及多个线程将同一个对象传递给不同的this调用。由于您传递的是非get参数,因此将假定const正在修改其get参数。因此,在同一对象上调用tuple计数从多个线程修改对象。因此,调用它可以合法地引发get上的数据竞争。

即使从技术上讲,它只是从tuple中提取子对象,因此不应该干扰对象本身或其他子对象。标准不知道这一点。

但是,如果参数为tuple,则const不会被视为引发与get const次调用的数据争用}。这些只是从多个线程中查看相同的对象,这在标准库中是允许的。它会引发数据竞争,使用getconst次使用或get对象的其他非const次使用。但不是tuple使用它。

所以你可以“访问”它们,但不能“修改”它们。

答案 1 :(得分:-1)

简短的回答是,它取决于process而不是get的类型和内容。 get本身只检索对象的地址并将其作为引用返回。检索地址主要是读取整数的内容。它不会引发竞争条件。粗略地说,当且仅当以下是线程安全的时,您的问题中的代码片段是线程安全的,

T1 t1;
T2 t2;
T3 t3;

std::thread{[&]{process(t1);}}.detach();
std::thread{[&]{process(t2);}}.detach();
std::thread{[&]{process(t3);}}.detach();
相关问题