- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在这个示例程序中,我试图避免使用前向声明和利用 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;
}
最佳答案
您正在传递对函数局部的引用 f
到 lambda body
,由 thread
调用构造函数。
当线程函数到达body
内部的调用时,该对象可能不再存在.
扩展一下:
由 run
创建的新线程将执行 body
的拷贝, 这是一个包含对对象 [&f]
的引用 ( f
) 的 lambda , 具有函数范围 run
当主线程离开时将被销毁 run
.
线程函数会调用operator()
关于其引用 f
在 f(this)
行中在 body
.如果 run
发生,此调用已经导致未定义的行为在线程函数执行此调用之前,主线程到达范围结束。这里的数据竞争是,主线程可能会写入 f
的访问内存。销毁它,与对 f
的内存的读取访问不同步在生成的线程中。
完全可以避免中间函数对象:
template<typename F>
void run(const F& f){
auto body = [this](){
f(this);
};
tid=new std::thread(body);
}
这将采用外层 lambda data_race
作为引用,将此引用复制到 body
而且,只要你确定 data_race
在 main
超过所有线程,避免了前面提到的数据竞争。
您编辑的代码做了类似的事情,即它消除了 run
的本地对象. a
在 body
将引用 A
在 main
中定义其中,只要main
保证其生命周期超出线程的生命周期,此时不会引起任何问题。
关于c++ - ThreadSanitizer 检测到数据竞争,问题出在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57741185/
我正在使用启用了线程清理器的 Clang-8 来编译下面的代码 std::atomic ptr {nullptr}; int data {0}; void producer() { std::st
我使用带有 -g3 和 -O1 标志的 Clang 进行编译,但是 TSan 提示说它发现了数据争用并且它输出了一个完全模糊的堆栈跟踪,没有清晰的行号。 在这种情况下如何查找行号? Pastebin
我的应用程序使用了 wxWidgets 库,它是通过 gcc 5.1.0 从源代码构建的,使用 -g 和 -O0 我使用 clang++36 -g -fsanitize=thread -stdlib=
在这个示例程序中,我试图避免使用前向声明和利用 lambda 函数(称为 data_race)的循环依赖 struct B{ int x; std::thread* tid;
Clang 有 -fsanitize-blacklist 编译开关来抑制来自 ThreadSanitizer 的警告。不幸的是,我无法让它工作。 这是一个我想抑制的例子: WARNING: Threa
我一直在努力让 ThreadSanitizer 与我拥有的 gcc 版本 (4.8.2) 一起工作,所以我采用了他们的简单示例: #include #include #include #incl
我将其归结为一个简单的独立示例。主线程入队 1000 个项目,一个工作线程尝试同时出队。 ThreadSanitizer 提示其中一个元素的读取和写入之间存在竞争,即使有一个获取-释放内存屏障序列保护
我想知道线程清理程序(clang)的死锁在哪里,但问题是程序被阻塞,并且在使用 -fsanitize=thread 选项编译期间未检测到死锁。并且执行结束没有任何结果,因为程序被阻塞(由于死锁而无法退
谁知道ThreadSanitizer ?有没有人在 windows (xp) 上使用这个工具?我从 here 下载最新版本.我为 VS2008 编写了测试应用程序(使用单个 printf("hello
ThreadSanitizer suppression files 之间有区别吗?和 blacklist files ? -- 当由 -fsanitize-blacklist= 的 llvm 特定编译
或者我必须使用单独的版本吗? -fsanitize 标志仅允许地址或线程,但是否允许多个? 问候 最佳答案 不,不可能将 AddressSanitizer 和 ThreadSanitizer 组合到一
我的自旋锁实现如下所示,我认为它不会导致任何数据竞争,但是当我使用 -fsanitize=thread 测试我的代码时,它报告 spin_unlock 有写数据竞争。怎么会这样?是误报吗? #defi
我正在使用ThreadSanitizer进行线程分析,并且收到一条警告,该警告使我对互斥锁的工作方式的理解非常困惑。我在Debian Stretch上使用gcc 6.3。 在一个类中,在一个线程中,我
请看下面的代码: #include #include class ReferenceCounted { public: ReferenceCounted() : ref_count_(
有没有人试过clang's ThreadSanitizer与 Intel Threading Building Blocks (TBB) ? 到目前为止,我的经验是您会收到很多警告,即使对于相对简单的
我使用 asm 编写了 atomic_inc 来递增整数,它实际上用于引用共享对象的计数。 gcc 4.8.2 -fsanitize=thread 报告数据竞争,我终于发现这可能是由我的 atomic
我是一名优秀的程序员,十分优秀!