2

I'm studying the effects that compiler optimizations (specifically, instruction reordering here) may have for a multi-threaded program.

Let's say we have a reader thread and a writer thread.

// Global shared data between threads
bool data;
bool flag = false;

// writer.cpp
void writer()
{
    data = true;  // (1)
    flag = true;  // (2)
}

// reader.cpp
void reader()
{
    if (flag)
    {
       count << data;
    }
}

May a C++11-compliant compiler reorder instruction (1) and (2)

According to C++ "as-if" rule, the transformation shouldn't change a program's observable behavior. Apparently, when compiling the writer, a compiler generally can't be sure whether reordering (1) and (2) will change the program's observable behavior or not, because data and flag are both globals which may affect another thread's observable behavior.

But it states here that this kind of reordering can happen, see memory ordering at compile time.

So do we need a compiler barrier between (1) and (2)? (I'm well aware of possible CPU reordering. This question is only on compiler reordering)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Eric Z
  • 14,327
  • 7
  • 45
  • 69
  • 1
    is this about reordering of memory accesses (instruction reordering), or about reordering variables in memory (changing the memory layout)? – jalf Aug 24 '14 at 14:16
  • It's about instruction reordering. Refer to [here](http://preshing.com/20120625/memory-ordering-at-compile-time/) – Eric Z Aug 24 '14 at 14:18
  • 1
    @EricZ: Fixed your title accordingly. – Lightness Races in Orbit Aug 24 '14 at 14:19
  • @LightnessRacesinOrbit Thanks, but I'd also like to know if loads can be reordered as well. – Eric Z Aug 24 '14 at 14:22
  • @EricZ: See, that's the first time you've mentioned it. Please take more care over your questions in future. – Lightness Races in Orbit Aug 24 '14 at 14:24
  • 1
    I'd think that instruction reordering is apparent from the context. How is "reordering variables in memory" related by the way? – Eric Z Aug 24 '14 at 14:32
  • 2
    "I'm well aware of possible CPU reordering. This question is only on compiler reordering" - so you don't care if your program is broken because the cpu reordered it, but you do if the compiler does? – Voo Aug 24 '14 at 15:43
  • @Voo, this is all about as-if rule in the language. I'm saying so to avoid the unnecessary deviation of the topic. – Eric Z Aug 24 '14 at 23:31
  • @EricZ The so called "as if rule" doesn't cover assembly code, it covers possible executions; CPU reordering is part of it. – curiousguy Jun 02 '18 at 19:33

2 Answers2

7

Absolutely they may. The compiler has no obligation whatsoever to consider side effects to other threads or hardware.

The compiler is only forced to consider this if you use volatile or synchronization (and those two are not interchangable).

The Standard memory model is known as SC-DRF, or Sequentially Consistent Data Race Free. A data race would be exactly the scenario you've just described- where one thread is observing non-synchronized variables whilst another is mutating them. This is undefined behaviour. Effectively, the Standard explicitly gives the compiler the freedom to assume that there are no other threads or hardware which is reading non-volatile non-synchronized variables. It is absolutely legitimate for a compiler to optimize on that basis.

By the way, that link is kinda crap. His "fix" does not fix anything at all. The only correct fix for multi-threaded code is to use synchronization.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • There is nothing wrong with that link. He just focuses on compile-time reordering and omit the other parts. He doesn't say that code fixes everything single issue of synchronization, which he does include in other posts. – Eric Z Aug 24 '14 at 14:37
  • Does that mean "as-if" rule applies to single-thread only? I'm puzzled mainly because it mentions "program" instead of "single thread", which to me, is multithread aware in C++11, which means that "observable behavior" includes those from multiple threads. – Eric Z Aug 24 '14 at 14:41
  • @EricZ The as-if rule only applies to correct programs. A program that contains a data race ("data race" has a specific definition that includes things that you might not think are data races) is not a correct program, therefore the implementation may make optimisations that are only valid for programs that do not contain data races. –  Aug 24 '14 at 15:36
  • @Eric it's simple - the given program's behavior is undefined since we have unsychronized reads and writes at the same time. Consequently whatever else the standard says is void and null. – Voo Aug 24 '14 at 15:36
  • @hvd Right, it's all about undefined behavior. The devil is in the details, again. Thanks;) – Eric Z Aug 24 '14 at 23:45
2

You have already asked this question on comp.lang.c++.moderated a week and a half ago, and you were given a complete explanation about the relationship between the C++11 requirements for sequencing within a single thread and for "happens before" relationships on synchronization between threads, here: https://groups.google.com/forum/#!topic/comp.lang.c++.moderated/43_laZwVXYg

What part of that reply didn't you understand, and we can try again?

Chris Vine
  • 677
  • 3
  • 7