int foo(int *x) {
*x = 0;
// wait until another thread writes to *x
return *x;
}
Can the C compiler really optimize foo to always return 0? That seems extremely unintuitive to me. int foo(int *x) {
*x = 0;
// wait until another thread writes to *x
return *x;
}
Can the C compiler really optimize foo to always return 0? That seems extremely unintuitive to me.Yes
> That seems extremely unintuitive to me.
C compilers are extremely unintuitive. This is a relatively sane case, they do things that are much more surprising than this.
It's very common for beginner embedded programmers to forget to do this and spend hours debugging why the register doesn't change when it should.
[1] https://en.m.wikipedia.org/wiki/Volatile_(computer_programmi...
At lower levels, you might have something like an IPC primitive there, which would be protected by a spinlock or similar abstraction, the inline assembly for which will include a memory barrier.
And even farther down still, the memory pointed to by "x" might be shared with another async context entirely and the "wait for" operation might be a delay loop waiting on external hardware to complete. In that case this code would be buggy and you should have declared the data volatile.
This is a wrong, a memory barrier would not salvage this code from UB. The read from `x` must at the very least be synchronized, and there might be other UB lurking as well.
You're right that if you try to write async code with only compiler instrumentation, you're very likely to be introducing race conditions (to be clear: not necessarily on architectures with sufficiently clear memory ordering behavior -- you can play tricks like this in pure C with x86 for instance). But that wasn't the question at hand.
int volatile *x
as the parameter to get the changes from a different thread.