NoS*_*tAl 3 c++ race-condition range-v3 c++20
运行此代码时,线程清理程序会抱怨数据竞争。为什么?
#include <iostream>
#include <ranges>
#include <thread>
#include <vector>
int main(){
std::vector v{11,22,33,44,55,66};
auto view = v | std::ranges::views::filter([](const auto x){
return x>47;
});
std::jthread jt1([&]{
int sum =0;
for (const auto& val: view) {sum+=val;}
});
std::jthread jt2([&]{
int sum =0;
for (const auto& val: view) {sum+=val;}
});
}
Run Code Online (Sandbox Code Playgroud)
注意:我知道这个答案,我最近在看一个演讲中学到了它,但我发现它非常令人惊讶并且没有与此相关的现有问题,所以我想分享它。如果没有人有兴趣回答,我会自己回答。
[&]在线程运行的 lambda 中应该立即响起警报。通过不const引用线程来传递随机对象通常是不安全的。特别是,const在标准库对象上调用非成员函数不是线程安全的。
begin不是 的const成员函数std::ranges::filter_view。
constexpr iterator begin();
期待:pred_.has_value()。
返回:{*this, ranges::find_if(base_, ref(*pred_))}。
备注:为了提供范围概念所需的分摊常数时间复杂度,该函数将结果缓存在 中以filter_view供后续调用使用。
在 libstdc++ 实现中,正是这种缓存操作触发了线程清理器。
试图使view常量导致编译错误。
也是如此reverse_view。
其他系列适配器确实有const对过载begin。
在实践中可以通过view.begin()在构造线程之前调用来解决这个问题。我不知道这是否会使未定义的行为正式消失(我认为它可能应该),但它确实使消毒剂静音。