9

I have some questions connected with memory model in C++11.

On https://www.think-cell.com/en/career/talks/pdf/think-cell_talk_memorymodel.pdf on the 29. slide is written

The C++ memory model guarantees sequential consistency

But, in my previous posts I learnt that C++ memory has weak memory model- the compiler can make reorder as he wants- he has to satisfy as if rule.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Gilgamesz
  • 4,727
  • 3
  • 28
  • 63

3 Answers3

12

The C++ memory model guarantees sequential consistency if you use atomic operations with the appropriate memory orderings to guarantee sequential consistency. If you just use plain non-atomic operations, or relaxed atomics, and no mutexes, then sequential consistency is not guaranteed.

Compilers are free to re-order operations if the difference in behaviour cannot be observed, that's the as-if rule. So for example, if re-ordering sequentially consistent atomics would produce a different observable result then it doesn't meet the as-if rule. If it would not produce a different observable result, then reordering is allowed.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 1
    update, the slides aren't being sloppy, so I deleted my prev comment. See my answer for what I think they mean there. Still, one slide shouldn't make you doubt all the other evidence that [C++'s default software memory model is weak/relaxed](http://preshing.com/20120930/weak-vs-strong-memory-models/), which includes a zillion web pages and the actual behaviour of compilers. – Peter Cordes Jul 19 '16 at 09:43
  • Amazing! Is compiler allowed to reorder the atomic operations with sequential consistency ? – choxsword May 04 '18 at 14:53
  • @Olumide detecting data races is not possible in general, so the compiler is not required to detect them. Data races are UB, so the compiler can assume they never happen, and it's your job to avoid them (e.g. by using atomic operations for accessing any shared data). I don't know what you mean by "back off from adding fences". It sounds like you should ask your own question, not try to hijack the comments here for new questions. – Jonathan Wakely Nov 26 '18 at 13:36
  • @JonathanWakely I thought so re ability the detect races. I've just read about Sequential Consistency for Race-Free Programs where the compiler adds fences to preserve the appearance of sequential consistency. This made me wonder what happens if there *are* races. I guess the short answer is that all bets are off. (I'll stop hijacking this thread now) – Olumide Nov 26 '18 at 13:43
6

I think I figured out what that slide is talking about, from reading the earlier slides:

slide 12: sequential consistency [Leslie Lamport, 1979]
the result of any execution is the same as-if

  1. the operations of all threads are executed in some sequential order
  2. the operations of each thread appear in this sequence in the order specified by their program

slide14: sequential consistency for data-race-free programs
SC-DRF:

  • We take care our program does not contain data races
  • The system guarantees sequentially consistent execution

So on slide 29, the authors are saying that once you avoid data-race UB using std::atomic, the program runs as-if everything happened in program order. (If all your std::atomic operations use the default memory_order_seq_cst).

This is an interesting way to look at C++'s weak (for non-atomic objects) memory model. This looks like a good set of slides. SC atomic operations are strongly ordered, and are kind of like one-way barriers for non-atomic operations. (And for relaxed atomic operations if you have any).

Note that being data-race-free means you can't look at non-atomic variables at arbitrary times, only when you've established that no other thread is writing them. (Usually via a synchronizes-with relationship with an acquire load seeing a release store done by the writer, or a mutex.) The data-race-free part is the key here; it's very easy to have data-race UB if you're not careful. When compiling to asm for real CPUs, this means non-atomic accesses can work as normal, while atomic<T> seq_cst accesses need to block compile-time and run-time reordering. https://preshing.com/20120625/memory-ordering-at-compile-time/


Part two: Please don't make a habit of asking two very different questions at once.

This "how does the CPU do it?" question would be a better fit as part of your later question: Atomicity on x86

I have most of an answer to it already written, which I'll put there instead.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • The obvious issue here is that data race free is only possible if you avoid UB; but avoiding UB is only well defined for sequential programs. So sequential consistency relies on sequential interpretation of program. So the whole thing is ill defined! – curiousguy May 03 '20 at 22:59
-6

The only possible way to define semantics for a language with undefined behavior is by describing sequential execution. Ergo, all programs behave as with sequential execution, or no program has defined behavior.

The idea that you have both in C/C++ is a hoax. Programs must behave sequentially for the semantics to make sense.

curiousguy
  • 8,038
  • 2
  • 40
  • 58