2
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>

bool m_ok = false;

void* run(void*)
{
    usleep(1000000);
    m_ok = true;
    printf ("Good bye!\n");
    return nullptr;
}   

int main() {
    pthread_t my_thread;
    pthread_create(&my_thread, nullptr, &run, nullptr);
    while (!m_ok)
        continue;
    printf("YES!!!\n");
    return 0;
}

When I compiled the above code with following commands, everything was good:

$ g++ test.cpp -lpthread -std=c++11
$ clang++ test.cpp -lpthread -std=c++11

But when I tried to use optimization flags, my program didn't finish. I tested all of following commands:

$ g++ test.cpp -lpthread -std=c++11 -O1
$ clang++ test.cpp -lpthread -std=c++11 -O1
$ g++ test.cpp -lpthread -std=c++11 -O2
$ clang++ test.cpp -lpthread -std=c++11 -O2

Also the versions of my g++ and clangs were:

$ g++ --version
g++ (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ clang++ --version
Debian clang version 3.2-7ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2)
Target: x86_64-pc-linux-gnu
Thread model: posix
m.elahi
  • 691
  • 6
  • 9
  • Do realize that C++11 has a standard thread class and sleep function. Also, reading from `m_ok` while writing to it is undefined behaviour AFAIK. Being UB would enable the compiler to say that it will never change. – chris Jun 09 '14 at 18:03
  • 2
    Use `std::atomic` – Jarod42 Jun 09 '14 at 18:05
  • 8
    It is technically undefined behavior to have an unguarded race-condition involving a write in C++11. – Mysticial Jun 09 '14 at 18:05
  • 2
    UB aside, what's probably happening here is that the compiler is promoting `m_ok` into a register. So it never sees the "update" coming from the other thread. Make it `volatile` and it'll probably behave as you expect. But I'm not sure what the standard says about race-conditions over volatile variables. – Mysticial Jun 09 '14 at 18:08
  • 7
    Whenever multiple compilers agree that your code has a bug, your first assumption should be that your code really does have a bug. –  Jun 09 '14 at 18:08
  • 1
    Fun reading: [link](http://stackoverflow.com/a/82306/335858). – Sergey Kalinichenko Jun 09 '14 at 18:11
  • dear chris and jardo42, Actually I have only one writer thread and one (or more) reader threads and it doesn't matter if reader threads temporary read a wrong value of shared value; but it is important that finally they read the correct value. Also I need a very high performance solution, so I can't use mutex, or std::atomic (I heard g++ 4.7+ have lock-free std::atomic, but I should test it). – m.elahi Jun 09 '14 at 18:38
  • @Mysticial Thanks a lot! as you said I should use `volatile`. But about race condition, I think a race condition occurs when 2 or more threads wants to modify a variable; here I have just one writing thread. – m.elahi Jun 09 '14 at 18:59
  • 1
    @m.elahi No, a race condition is when you have 2 or more threads accessing a variable and at least one of them is modifying it. So a read and a write from different threads counts as a race condition. – Mysticial Jun 09 '14 at 19:00
  • @Mysticial Yes, you are right! It seems it is also considered as a race condition! – m.elahi Jun 09 '14 at 19:30

1 Answers1

5

No. The C and C++ memory models do not permit cross-thread interactions for non-atomic variables, or when not protected by a mutex/lock. This is a data race and in violation of the abstract machine, so the optimizer is perfectly within its rights to launch Nethack.

The optimizer is written to assume, as it is explicitly permitted to do so by Standard, that external sources (including other threads) cannot magically mutate your program's state without explicit control by the user.

Puppy
  • 144,682
  • 38
  • 256
  • 465