0

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

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

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

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

4

2 回答 2

4

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

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

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

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

于 2019-05-29T02:58:47.893 回答
2

物理机的“相同地址”与 C++ 内存模型无关。C++ 内存模型讨论了抽象机器的行为。抽象机器中的地址在基本方式上是无法比较的,即使它们在不同时间具有相同的机器地址。

C++ 抽象机中的竞争条件是在其中讨论操作,而不是在物理机上。编译器的工作是确保 C++ 代码的抽象机器行为的物理机器实现是一致的。

如果它做了一些奇怪的事情,比如在线程之间重用堆栈地址空间,那么它会做任何它必须做的事情,以保持在抽象机器中访问不相关变量的竞争条件的缺乏。这些都不会发生在 C++ 代码级别。不namespace std涉及 C++ 代码(可能 in 除外)。

于 2019-05-29T02:50:16.350 回答