For fun I’m writing my own threading library used by me and a friend or two. First thing I’d like to write is a mutex
It appears I’m generating the assembly I want.
__atomic_fetch_add seems to generate
lock xadd and
__atomic_exchange seems to generate
xchg (not cmpxchg). I use both with
__ATOMIC_SEQ_CST (for now I’ll stick to that)
If I am using
__ATOMIC_SEQ_CST will gcc or clang understand these are synchronizing function? If I write
lock(); global++; unlock(); will any compilers move
global++; before or after the lock/unlock function? Do I need to call
__sync_synchronize(); for any reason? (they seem to do the same thing on x86-64). https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync seems to suggest my understanding is correct but its easy to misread documentation and I sometimes wonder if scope plays a part in these rules.
I think using those intrinsic the behavior of code in between a lock/unlock will act the same way as a pthread mutex lock/unlock?
If I am using __ATOMIC_SEQ_CST will gcc or clang understand these are synchronizing function?
Yes, that is the entire reason for these primitives to have memory ordering semantics.
The memory ordering semantics accomplish two things: (1) ensure that the compiler emits instructions that include the appropriate barriers to prevent reordering by the CPU; (2) ensure that compiler optimizations do not move code past those instructions in ways that the barrier should forbid.
If I write lock(); global++; unlock(); will any compilers move global++; before or after the lock/unlock function?
They will not. Again, that is the whole point of being able to specify memory ordering.
Do I need to call __atomic_thread_fence(__ATOMIC_SEQ_CST); or __sync_synchronize(); for any reason?
Not in this setting, no.