posix standard says that things like mutex will enforce a memory sync.
However, the compiler may reorder the memory access.
Say we have
lock(mutex);
setdata(0);
ready = 1;
unlock(mutex);
It might be changed to code below by compiler reordering, right?
ready = 1;
lock(mutex);
setdata(0);
unlock(mutex);
So how can mutex sync the memory access? To be more precise, how do compilers know that reordering should not happen across lock/unlock?
actually here for single thread aspect, ready assignment reorder is totally safe since ready is not used in function call lock(mutex).
EDITED:
So if function call is something that compiler will not get across,
can we regard it as a compiler memory barrier like
asm volatile("" ::: "memory")
General answer is that your compiler should support POSIX if you want to use it for POSIX targets, and that support means it should know to avoid reordering across lock and unlock.
That said, this kind of knowledge is commonly achieved in a trivial way: compiler would not reorder access to (non-provably-local) data across a call to an external function which may use or modify them. It should have known something special about
lockandunlockto be able to reorder.And no, it’s not that simple as “a call to global function is always a compiler barrier” — we should add “unless the compiler knows something specific about that function”. It does really happen: e.g.
pthread_selfon Linux (NPTL) is declared with__const__attribute, allowinggccto reorder acrosspthread_self()calls, even eliminating unnecessary calls altogether.We can easily imagine a compiler supporting function attributes for acquire/release semantics, making
lockandunlockless than a full compiler barrier.