反复读取其他线程写入数据是否为数据竞争?多线程代码线程安全性确认
关于多线程数据竞争的两个问题解答
问题1:反复读取另一个线程写入的特定数据是否属于数据竞争?
算。根据C++标准,数据竞争的定义是:两个线程同时访问同一个非原子对象,且至少有一个操作是写入,并且没有使用任何同步机制(比如互斥锁、原子操作、内存屏障)协调这些访问。哪怕是一个线程反复读、另一个线程写,只要满足上述条件,就属于数据竞争,会导致程序出现未定义行为——本地运行正常不代表所有环境都没问题,编译器或CPU的优化可能让读写操作的可见性、执行顺序出现异常。
问题2:请确认以下C++多线程代码(排除控制台输出部分)是否线程安全,变量是否存在数据竞争?
这段代码存在数据竞争,不属于线程安全代码,虽然本地运行正常,但在其他环境可能触发未定义行为,具体分析如下:
先贴出代码:
#include <iostream> #include <thread> using namespace std; int a = 0; bool alive = 1, start = 0; void detector() { int local_a = 0; while (alive) { if (start) { if (a != local_a) { cout << " change detected!\n"; local_a = a; } start = 0; } } } int main(int argc, char *argv[]) { std::thread t(detector); int count = 10; while (count--) { a = rand(); start = 1; cout << a << '\n'; while (start) { }; } alive = 0; t.join(); return 0; }
代码中的全局变量a、alive、start都是普通非原子变量,线程间的读写完全没有同步机制:
- 针对
start:主线程写入start=1后循环等待其变为0,detector线程读取start后写入start=0。由于没有同步,CPU可能将start的值缓存到寄存器中,导致主线程的写入无法及时被detector线程看见,或者detector线程的写入无法及时被主线程看见,直接触发死循环。 - 针对
a:主线程先执行a=rand()再执行start=1,但编译器或CPU可能重排序这两个操作——也就是start=1先执行,a的赋值还未完成,此时detector线程读取a会拿到旧值,导致逻辑错误。 - 针对
alive:主线程最后写入alive=0,detector线程的while(alive)循环可能因为编译器优化,直接将alive的值缓存起来,永远看不到alive=0的修改,导致detector线程无法退出。
你提到的“读写操作时总有一方等待特定值”只是逻辑层面的顺序,但没有通过C++标准认可的同步机制来保障,因此无法避免编译器和CPU优化带来的可见性、重排序问题,本质上仍存在数据竞争。
内容的提问来源于stack exchange,提问作者Suryansh Dey
相关产品推荐
相关产品推荐

