【发布时间】:2019-08-31 19:47:44
【问题描述】:
在这个示例程序中,我试图避免使用前向声明和循环依赖来利用 lambda 函数(称为 data_race)
struct B{
int x;
std::thread* tid;
B(int _x){
x = _x;
tid = NULL;
}
~B(){
if(tid != NULL) delete tid;
}
void run(std::function<void(B*)> f){
auto body = [&f, this](){
f(this);
};
tid=new std::thread(body);
}
void wait(){
tid->join();
}
};
struct A{
int x;
std::mutex mtx;
A(int _x){
x = _x;
}
void foo(B* b){
std::unique_lock<std::mutex> lock(mtx);
x = b->x;
};
};
int main(){
A a(99);
std::vector<B> v;
auto data_race = [&a](B* b){ a.foo(b);};
for(int i=0; i<10; i++){
v.push_back(B(i));
}
for(int i=0; i<v.size(); i++){
v[i].run(data_race);
}
for(int i=0; i<v.size(); i++){
v[i].wait();
}
return 0;
}
但是 ThreadSanitizer 检测到来自 lambda 函数 data_race 的数据竞争。你能帮我理解为什么吗? A 内部的互斥体应该足以避免它。另外,你能帮我找到解决办法吗?
编辑:使用前向声明,不再检测到数据竞争,为什么? (只发结构体,不发主文,长帖见谅)
struct B;
struct A{
int x;
std::mutex mtx;
A(int _x){
x = _x;
}
void foo(B* b);
};
struct B{
int x;
std::thread* tid;
B(int _x){
x = _x;
tid = NULL;
}
~B(){
if(tid != NULL) delete tid;
}
void run(A& a){
auto body = [&a, this](){
a.foo(this);
};
tid=new std::thread(body);
}
void wait(){
tid->join();
}
};
void A::foo(B* b){
std::lock_guard<std::mutex> lock(mtx);
x = b->x;
}
【问题讨论】:
-
赋值
x = b->x;将导致x的结果值来自随机的B对象,即使访问已正确同步。 -
同样不相关的注意:你的类
B违反了0/3/5的规则并且会导致未定义的行为,如果任何B,在它上面调用run之后,被复制/移动, 或在没有事先调用wait的情况下被销毁,这可能在run调用之后修改v时发生。 -
旁注:新的 std:: 线程没有意义。
标签: c++ multithreading c++11 concurrency data-race