关于含潜在data race的多线程C++程序实际执行合理性的问询
C++多核环境下该多线程程序的数据竞争发生概率分析
你已经明确「数据竞争是执行的属性,而非抽象程序的属性」——也就是只要两个线程实际上(而非理论上)不同时访问共享变量(且至少一个是写操作),程序行为就是良定义的。现在针对以下C++程序探讨:
#include <iostream> #include <thread> #include <unistd.h> constexpr int sleepTime = 10; void func(int* ptr) { sleep(sleepTime); std::cout<<"going to delete ptr: "<<(uintptr_t)ptr<<"\n"; delete ptr; std::cout<<"ptr has been deleted\n"; } int main() { int* l_ptr = new int(5); std::thread t(func, l_ptr); t.detach(); std::cout<<"We have passed ptr: "<<(uintptr_t)l_ptr<<" to thread for deletion. Val at ptr: "<<*l_ptr<<"\n"; std::cin.get(); }
问题
该程序仅当主线程与子线程同时访问共享变量时才存在数据竞争,请问在多核CPU环境下,实际发生这种情况是否极不可能?
回答
实际发生数据竞争的概率确实极低,但绝非不可能。
具体分析:
- 子线程启动后第一时间调用了
sleep(10),这会让它挂起10秒,之后才会执行delete ptr(这属于对共享内存的写操作,因为释放内存会修改内存的状态)。 - 主线程在创建并分离子线程后,会立刻执行包含
*l_ptr读操作的std::cout语句,这个操作会在子线程挂起的10秒窗口内快速完成,之后主线程就卡在std::cin.get()等待输入了——此时子线程才会醒来执行delete。
从时间线来看,两者的访问操作窗口几乎完全错开,所以绝大多数情况下不会出现同时访问的情况。
但极端情况依然存在:比如主线程执行到*l_ptr的读操作时,刚好被操作系统中断,调度器把CPU时间片切给子线程,而子线程此时刚好用完10秒的睡眠时间,开始执行delete ptr——这种情况下就会出现读和写操作同时发生,触发数据竞争。
这种极端情况的触发概率极低,但从C++标准的角度来说,只要存在理论上的可能性,程序就属于未定义行为,绝对不能依赖这种低概率来保证程序安全。
内容的提问来源于stack exchange,提问作者Vishal Sharma
相关产品推荐
相关产品推荐

