首页 > 解决方案 > 什么保证两个不相关线程中的不同不相关对象没有(不可避免的)竞争条件?

问题描述

当不同的线程只使用不相关的对象并且字面上不共享任何东西时,它们就不能有竞争条件,对吧?明显地。

实际上所有线程共享一些东西:地址空间。不能保证一个线程使用的内存位置不会在其他时间分配给另一个线程。这对于动态分配对象甚至自动对象的内存来说都是如此:没有规定多个线程的“堆栈”(函数的本地对象)的内存空间是预先分配的(甚至是延迟分配的)、不相交的和表示为通常的线性“堆栈”;它可以是任何具有堆栈(FILO)行为的东西。因此,用于存储自动对象的内存位置可以稍后被另一个线程中的另一个自动对象重用。

这本身似乎是无害且无趣的,因为如何为自动对象腾出空间仅在缺少空间时才重要(非常大的自动数组或深度递归)。

同步呢?不相关的不相交线程显然不能使用任何 C++ 同步原语来确保正确同步,因为根据定义,没有任何东西 (to) 同步 (on),因此在线程之间创建关系之前不会发生任何事情。

如果在线程1中销毁局部变量并退出后,实现重用堆栈的内存范围foo()(包括的位置)来存储线程2中的变量怎么办?ifoo()bar()

void foo() { // in thread 1
   int i;
   i = 1;
}

void bar() { // in thread 2
   int i;
   i = 2;
}

在和之前没有发生过i = 1i = 2

这会导致数据竞争和未定义的行为吗?

换句话说,所有多线程程序是否都有可能基于用户无法控制的实现选择产生未定义的行为,这是不可预见的,并且对于他无能为力的种族?

标签: c++multithreadinglanguage-lawyermemory-modeldata-race

解决方案


C++ 内存模型的行为并不像您可能直观地期望的那样。例如,它有内存位置,但引用 N4713 草案第 6.6.1 节第 3 段:

内存位置要么是标量类型的对象,要么是所有具有非零宽度的相邻位域的最大序列。[注意:语言的各种特性,例如引用和虚函数,可能涉及程序无法访问但由实现管理的额外内存位置。—尾注] 两个或多个执行线程 (6.8.2) 可以访问单独的内存位置而不会相互干扰。

因此,根据 C++ 内存模型,不同线程中的两个不同对象永远不会被认为具有相同的内存位置,即使在物理机级别,一个在另一个被释放后被分配到同一个 RAM 中。

根据 C++ 内存模型,您询问的情况不是数据竞争。无论硬件的内存模型如何,实现都必须采取任何必要的步骤来确保这是安全的。


推荐阅读