使用两个线程在C/C++中操作不同的数组索引时,是否需要同步?

ACc*_*tor 11 c c++ arrays multithreading synchronization

假设我有一个如下定义的数组:

volatile char v[2];
Run Code Online (Sandbox Code Playgroud)

我有两个线程(分别用A,B表示)操作数组v.如果我确保A,B在任何时候使用不同的索引,也就是说,如果A现在正在操纵v[i],那么B要么什么都不做,要么操纵v[1-i].我想知道这种情况需要同步吗?

我已经提到了这个问题,但我认为它在Java中是有限的.我之所以提出这个问题的原因是,我在一个大型项目中一直在努力解决一个奇怪而罕见的错误,直到现在,我能解释这个错误的唯一原因是需要同步以上操纵.(由于这个bug非常罕见,我很难证明我的推测是否属实)

编辑:可以读取和修改v.

T.C*_*.C. 9

就C++ 11和C11标准而言,您的代码是安全的.C++11§1.7[intro.memory] ​​/ p2,省略了无关的注释:

存储器位置或者是标量类型的对象或相邻位字段都具有非零宽度的最大序列.两个或多个执行线程(1.10)可以更新和访问单独的存储器位置,而不会相互干扰.

char是整体式的,这意味着它是一个算术类型,这意味着volatile char是一个标量型,所以v[0]v[1]是分开的存储器位置.

C11在§3.14中有类似的定义.

在C++ 11和C11之前,语言本身没有线程的概念,因此您将受到正在使用的特定实现的左右.


Sam*_*Sam 3

这可能是编译器错误或硬件限制。

有时,当从内存访问小于 32 位/64 位的变量时,处理器将读取 32 位,设置适当的 8 或 16 位,然后写回整个寄存器。这意味着它也会读/写相邻的内存,从而导致数据竞争。

解决方案是

  • 使用字节访问指令。它们可能不适用于您的处理器,或者您的编译器不知道如何使用它们。

  • 填充你的元素以避免这种共享。如果您的目标平台不支持字节访问,编译器应该自动执行此操作。但在数组中,这与内存布局要求相冲突。

  • 同步整个结构

C++03/C++11 争论

在经典 C++ 中,您需要避免/减轻这种行为。在 C++11 中,这违反了内存模型要求,如其他答案中所述。