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

时间:2022-09-23 21:00:28

Suppose I have an array defined as follows:

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

volatile char v[2];

And I have two threads (denoted by A, B respectively) manipulating array v. If I ensure that A, B use different indices at any time, that is to say, if A is now manipulating v[i], then B is either doing nothing, or manipulating v[1-i]. I wonder is synchronization needed for this situation?

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

I have referred to this question, however I think it is limited in Java. The reason why I ask this question is that I have been struggling with a strange and rare bug in a large project for days, and up to now, the only reason I could come up with to explain the bug is that synchronization is needed for the above manipulation. (Since the bug is very rare, it is hard for me to prove whether my conjecture is true)

我提到过这个问题,但是我认为它在Java中是有限的。我之所以问这个问题的原因是,我在一个大型项目中一直在与一个奇怪而罕见的bug做斗争,直到现在,我能想出一个解释bug的唯一原因是,上面的操作需要同步。(由于这个bug非常罕见,我很难证明我的猜想是否正确)

Edit: both reading and modifying are possible for v.

编辑:v可以阅读和修改。

3 个解决方案

#1


2  

It might be a compiler bug or a hardware limitation.

它可能是一个编译器错误或硬件限制。

Sometimes, when a less than 32-bit/64-bit variable is accesses from memory, the processor will read 32 bits, set the apprpriate 8 or 16 bits, then write back the whole register. That means it will read/write the adjacent memory as well, leading to a data race.

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

Solutions are

解决方案

  • use byte-access instructions. They may not be available for your processor or your compiler does not know to use them.

    使用byte-access指令。它们可能对处理器不可用,或者编译器不知道如何使用它们。

  • pad your elements to avoid this kind of sharing. The compiler should do it automatically if your target platform does not support byte access. But in an array, this conflicts with the memory layout reqiurements.

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

  • synchronize the whole structure
  • 同步整个结构

C++03/C++11 debate

c++ 03 / c++ 11辩论

In classic C++ it's up to you to avoid/mitigate this kind of behaviour. In C++11 this violates memry model requitements, as stated in other answers.

在经典的c++中,应该由您来避免/减轻这种行为。在c++ 11中,这违反了memry模型的要求,如其他答案所述。

#2


7  

As far as the C++11 and C11 standards are concerned, your code is safe. C++11 §1.7 [intro.memory]/p2, irrelevant note omitted:

就c++ 11和C11标准而言,您的代码是安全的。(介绍c++ 11§1.7。内存)/ p2,无关紧要的注意省略:

A memory location is either an object of scalar type or a maximal sequence of adjacent bit-fields all having non-zero width. Two or more threads of execution (1.10) can update and access separate memory locations without interfering with each other.

内存位置要么是标量类型的对象,要么是具有非零宽度的相邻位字段的最大序列。两个或多个执行线程(1.10)可以在不相互干扰的情况下更新和访问单独的内存位置。

char is a integral type, which means it's an arithmetic type, which means that volatile char is a scalar type, so v[0] and v[1] are separate memory locations.

char是一个整数类型,这意味着它是一个算术类型,这意味着volatile char是一个标量类型,所以v[0]和v[1]是单独的内存位置。

C11 has a similar definition in §3.14.

C11§3.14中也有类似的定义。

Before C++11 and C11, the language itself has no concept of threads, so you are left to the mercy of the particular implementation you are using.

在c++ 11和C11之前,语言本身没有线程的概念,所以您只能依赖于正在使用的特定实现。

#3


0  

You need to handle synchronization only if you are accessing the same memory and modifying it. If you are only reading then also you don't need to take care about the synchronization.

只有在访问和修改相同的内存时,才需要处理同步。如果您只是在阅读,那么也不需要注意同步。

As you are saying Each thread will access different indices then you don't require synchronization here. but you need to make sure that the two thread should not modify the same indice at the same time.

正如您所说的,每个线程将访问不同的索引,因此这里不需要同步。但是您需要确保两个线程不应该同时修改相同的标记。

#1


2  

It might be a compiler bug or a hardware limitation.

它可能是一个编译器错误或硬件限制。

Sometimes, when a less than 32-bit/64-bit variable is accesses from memory, the processor will read 32 bits, set the apprpriate 8 or 16 bits, then write back the whole register. That means it will read/write the adjacent memory as well, leading to a data race.

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

Solutions are

解决方案

  • use byte-access instructions. They may not be available for your processor or your compiler does not know to use them.

    使用byte-access指令。它们可能对处理器不可用,或者编译器不知道如何使用它们。

  • pad your elements to avoid this kind of sharing. The compiler should do it automatically if your target platform does not support byte access. But in an array, this conflicts with the memory layout reqiurements.

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

  • synchronize the whole structure
  • 同步整个结构

C++03/C++11 debate

c++ 03 / c++ 11辩论

In classic C++ it's up to you to avoid/mitigate this kind of behaviour. In C++11 this violates memry model requitements, as stated in other answers.

在经典的c++中,应该由您来避免/减轻这种行为。在c++ 11中,这违反了memry模型的要求,如其他答案所述。

#2


7  

As far as the C++11 and C11 standards are concerned, your code is safe. C++11 §1.7 [intro.memory]/p2, irrelevant note omitted:

就c++ 11和C11标准而言,您的代码是安全的。(介绍c++ 11§1.7。内存)/ p2,无关紧要的注意省略:

A memory location is either an object of scalar type or a maximal sequence of adjacent bit-fields all having non-zero width. Two or more threads of execution (1.10) can update and access separate memory locations without interfering with each other.

内存位置要么是标量类型的对象,要么是具有非零宽度的相邻位字段的最大序列。两个或多个执行线程(1.10)可以在不相互干扰的情况下更新和访问单独的内存位置。

char is a integral type, which means it's an arithmetic type, which means that volatile char is a scalar type, so v[0] and v[1] are separate memory locations.

char是一个整数类型,这意味着它是一个算术类型,这意味着volatile char是一个标量类型,所以v[0]和v[1]是单独的内存位置。

C11 has a similar definition in §3.14.

C11§3.14中也有类似的定义。

Before C++11 and C11, the language itself has no concept of threads, so you are left to the mercy of the particular implementation you are using.

在c++ 11和C11之前,语言本身没有线程的概念,所以您只能依赖于正在使用的特定实现。

#3


0  

You need to handle synchronization only if you are accessing the same memory and modifying it. If you are only reading then also you don't need to take care about the synchronization.

只有在访问和修改相同的内存时,才需要处理同步。如果您只是在阅读,那么也不需要注意同步。

As you are saying Each thread will access different indices then you don't require synchronization here. but you need to make sure that the two thread should not modify the same indice at the same time.

正如您所说的,每个线程将访问不同的索引,因此这里不需要同步。但是您需要确保两个线程不应该同时修改相同的标记。