【发布时间】:2019-06-07 16:05:28
【问题描述】:
以下代码块:
技术上无效,因为
std::get<>()不是线程安全的。参考:Is using `std::get<I>` on a `std::tuple` guaranteed to be thread-safe for different values of `I`?据我所知,现在和可预见的未来,在所有
std::tuple<>的实施中都是有效的。
#include <tuple>
#include <atomic>
#include <thread>
// Out of my control
using data_t = std::tuple<int, int, int, int>;
void foo(data_t);
//
int main() {
data_t landing;
std::atomic<int> completed = 0;
// Whichever thread pings last will be the one performing foo()
auto ping = [&](){
if(++completed == 4) {
foo(landing);
}
};
std::thread a([&](){ std::get<0>(landing) = 1; ping(); });
std::thread b([&](){ std::get<1>(landing) = 2; ping(); });
std::thread c([&](){ std::get<2>(landing) = 3; ping(); });
std::thread d([&](){ std::get<3>(landing) = 4; ping(); });
a.join();
b.join();
c.join();
d.join();
return 0;
}
为了让事情变得更有趣,实际的代码充满了可变参数模板,因此编写一个一次性着陆台结构来处理这种情况并不能解决问题。它必须是一个通用的解决方案。
我目前的选择是:
- 使用改写后的
std::get<>文档有效地重新实现std::tuple<>,这既浪费时间又浪费代码。 - 推动
std::get<>(std::tuple)的提案以提供类似于std::vector<>的保证,并记录代码仅在尚未发布的标准版本中有效的事实。 - 忽略这个问题,相信事实上,这几乎肯定总是有效的。
这些在短期内都不是特别好...所以我的问题是:
- 我是否遗漏了使第 2 点无效的内容?
- 是否有更好的解决方法可以让实现在技术上有效,而不必支持过多的额外代码。
- 欢迎对此主题提出任何其他意见。
【问题讨论】:
-
为什么一切都很糟糕?在我看来,第 2 点是一条可行的路——推送提案,一旦接受,就使用。附带说明一下,我看不出这个问题对已经提到的问题有什么补充。
-
@SergeyA 因为避免使用 UB 通常是个好主意?
-
向标准委员会提交您的第一份提案的绝佳机会!
-
@Frank 在答案中表达的相同概念刚刚获得了 5 票赞成,因此您可能会重新考虑这是一个糟糕的主意。
-
“并记录代码仅在尚未发布的标准版本中有效这一事实” - 您还可以考虑针对标准提出 defect图书馆。一些缺陷具有追溯应用的解决方案(例如 IIRC LWG2101)。
标签: c++ multithreading tuples language-lawyer c++17