Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When manipulating different array indices in C/C++ with two threads, is synchronization needed?

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?

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)

Edit: both reading and modifying are possible for v.

like image 897
ACcreator Avatar asked Sep 06 '14 05:09

ACcreator


2 Answers

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.

Solutions are

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

  • 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.

  • synchronize the whole structure

C++03/C++11 debate

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.

like image 152
Sam Avatar answered Nov 15 '22 15:11

Sam


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:

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.

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.

C11 has a similar definition in §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.

like image 36
T.C. Avatar answered Nov 15 '22 15:11

T.C.