Is it safe to assume that changing a global bool variable in threads without lock is crash safe?

Viewed 179

I know it is undefined behaviour. Hence the possibility of data race or crash. One can use atomicbool to avoid such possibilities. What I am interested to know about the crash safety.

AFAIU, crash may happen when one thread reads the partially written or torn value by another thread. On the other hand the size of the bool is implementation defined but it hardly make sense to have that greater than the size of pointer in a data model .

is it safe to assume that the memory block of bool will either be updated or not? Therefore, other thread cannot read the torn value hence it is crash safe to read/write global bool from different threads ?

2 Answers

No, it is not safe. Undefined behavior is undefined. There is no rule that says that it can't crash unless you can think of a way that it can crash. I can think of ways it can crash.

For example, suppose you have a function that creates a thread that reads from the same bool that the function writes to without synchronization. Since this is UB, the compiler is free to assume that function will never be called. It is not even required to generate any code for it. If that function is called by an if, the compiler can assume the other branch of the if will always be taken.

And don't you even think about saying "no compiler would ever be that smart". Lots of people used to say things like that and then got burned when compilers got smarter. Over the past decade or two, I've seen dozens of cases of "that new compiler broke my code" when, of course, the code was broken all along.

There have been compilers that have changed code like if (x > 2) y = 3; else y = 4; into code like y = 3; if (x <= 2) y = 4;. That can even be an optimization in some cases.

Don't intentionally make broken code.

It is pretty unlikely that you will trigger a crash, but you might trigger other unexpected results:

bool a_global_boolean = false;

void thread_1() {
  sleep(10);
  a_global_boolean = true;
}

void thread_2() {
  while (a_global_boolean == false) {
  }
}

You probably expect that thread_1 and thread_2 will return after 10 seconds. But for thread_2, the compiler is allowed to assume that a_global_boolean will never return, so when optimizations are enabled, that thread may never end.

https://repl.it/repls/UsefulLowAbstracttype#main.cpp (make sure you compile with -O3)

Related