Reputation: 783
This tutorial says the following:
every load on x86/64 already implies acquire semantics and every store implies release semantics.
Now say I have the following code (I wrote my questions in the comments):
/* Global Variables */
int flag = 0;
int number1;
int number2;
//------------------------------------
/* Thread A */
number1 = 12345;
number2 = 678910;
flag = 1; /* This is a "store", so can I not use a release barrier here? */
//------------------------------------
/* Thread B */
while (flag == 0) {} /* This is a "load", so can I not use an acquire barrier here? */
printf("%d", number1);
printf("%d", number2);
Upvotes: 1
Views: 203
Reputation: 23659
Let's assume that the code is written in C99 and the target architecture is x86. The strong memory model of x86 takes effect only at the machine code level. C99 doesn't have a memory model. I'll explain what can go wrong and discuss whether there is a C99-compliant way of handling the issues.
First, we have to make sure that none of the variables get optimized away and that all accesses to flag
, number1
, and number2
occur from memory rather than cached in CPU registers1. This can be achieved in C99 by qualifying all of the three variables with volatile
.
Second, we have to ensure that the store to flag
in the first thread has release semantics. These semantics include two guarantees: the store to flag
does not get reordered with previous memory accesses and making the store visible to the second thread. The volatile
keyword tells the compiler that accesses to the variable may have observable side effects. This prevents the compiler from reordering accesses to volatile variables with respect to other operations that are also considered to have observable side effects by the compiler. That is, by making all of the three variables volatile
, the compiler will maintain the order of all the three stores in the first thread. That said, if there are other non-volatile memory accesses that are above or below the store to flag
, then such accesses can still be reordered. So the standard volatile
provides only partial release semantics.
Third... actually for your particular piece of code, atomicity is not required. That's because the store to flag
only changes one bit, which is inherently atomic. So for this particular code, you don't have to worry about atomicity. But in general, if the store to flag
may change more than one bit and if the condition checked in the second thread may behave differently depending on whether it sees all or some of the bit changes, then you'd certainly need to ensure that accesses to 'flag` are atomic. Unfortunately, C99 has no notion of atomicity.
To get full release semantics and atomicity, you can either use C11 atomics (as discussed in the article you cited) or you can resort to compiler-specific techniques (also discussed in the article you cited). Of course, you can still just look at the generated machine code and see whether the x86 memory model itself offers the necessary requirements for correctness. This is not feasible on large code bases. In addition, the next time the code is compiled, the generated machine code may change. Finally, since you're merely a human, you may make a mistake.
(1) In the cited article, the variable A
is declared as a shared global variable. Now most probably the compiler will allocate it from memory. But is this strictly standard compliant? What prevents the compiler from allocating it in a register for the whole lifetime of the program? Not sure about that.
Upvotes: 1
Reputation: 64925
The tutorial is talking about loads and stores at the assembly/machine level, where you can rely on the x86 ISA semantics which include acquire-on-load and release-on-store.
Your code, however, is C
which provides no such guarantees at all, and the compiler is free to transform it to something entirely different than what you'd expect in terms of loads and stores. This isn't theoretical, it happens in practice. So the short answer is: no, it's not possible to do that portably, legally in C - although it might work if you get lucky.
Upvotes: 3