<I>在"std::tuple"上使用"std::get"是否保证对于"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
从多个线程并发改变它们是否安全,只要每个线程访问不同的元素?
例:
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
在规范中没有关于其数据竞争属性的明确声明,因此我们回退到[res.on.data.races]中定义的默认行为。具体而言,第2段和第3段讲述了这个故事:
C++ 标准库函数不得直接或间接访问由当前线程以外的线程访问的对象 (1.10),除非通过函数的参数直接或间接访问对象, 包括
this
.C++ 标准库函数不得直接或间接修改由当前线程以外的线程访问的对象 (1.10),除非通过函数的非
const
参数(包括this
)直接或间接访问对象。
这些仅针对与函数参数提供的同一对象不同的用途提供数据争用保护。从技术上讲,模板参数不是函数的参数,因此它不符合条件。
您的案例涉及多个线程将同一对象传递给不同的get
调用。由于您传递的是非const
参数,因此将假定get
正在修改其tuple
参数。因此,对同一对象调用get
计为从多个线程修改对象。因此,调用它可以合法地引发tuple
的数据竞赛。
即使从技术上讲,它只是从tuple
中提取一个子对象,因此不应该干扰对象本身或其其他子对象。标准不知道这一点。
但是,如果参数const
,则get
不会被视为引发与其他const
get
调用的数据竞争。这些只是从多个线程查看同一对象,这在标准库中是允许的。这将引发一场数据竞赛,非const
使用get
或tuple
对象的其他非const
用途。但不是const
使用它。
因此,您可以"访问"它们,但不能">修改"它们。
简短的回答是,这取决于类型和process
做什么而不是get
。就其本身而言,get
只是检索对象的地址并将其作为引用返回。检索地址主要只是读取整数的内容。它不会提高竞争条件。粗略地说,您问题中的代码片段是线程安全的,当且仅当以下内容是线程安全的,
T1 t1;
T2 t2;
T3 t3;
std::thread{[&]{process(t1);}}.detach();
std::thread{[&]{process(t2);}}.detach();
std::thread{[&]{process(t3);}}.detach();
- 通过网络、跨平台传递std::变体是否安全
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- std::memmove在同一对象之间是否始终安全
- 从其存储的回调中删除 std::函数是否安全
- 使用 std::vector::swap 方法在C++中交换两个不同的向量是否安全?
- 我可以对 std::array 使用自定义分配器来获取安全加密密钥吗?
- 安全回调提供程序(SFINAE,std::正向和过载解析)
- 如果迭代器没有因插入而无效,则使用std::find和C::insert()是线程安全的
- std::weak_ptr<T>::锁定线程安全吗?
- std::shared_ptr::unique(),复制和线程安全
- 通过std::shared_ptr使用Rcpp和RcppParallel的线程安全函数指针
- 附加类型安全的子类std::string
- 我们如何使std::uniform_int_distribution加密安全
- std::mutex作为一个成员变量对多个线程来说是安全的吗
- std::free线程安全吗
- 为什么我的 std::atomic<int> 变量不是线程安全的?
- 访问"std::vector"的保留但未调整大小的内存作为原始内存是否安全?
- c++类用STD安全指针相互链接(c++)