4 ms·
> spinlock=false; // Don't even need an atomic here actually No, you'll need a memory barrier there. On x86, sure you get away for free, because x86 memory mo
by vardump 7y ago
> spinlock=false; // Don't even need an atomic here actually
No, you'll need a memory barrier there. On x86, sure you get away for free, because x86 memory model says stores are never reordered with other stores.
On practically all other systems you'll need equivalent of C++ atomic "memory_order::release" to prevent stores from being reordered with other stores.
Otherwise you're in for a surprise. Without a (half) barrier, it'll be buggy on ARM, POWER, MIPS, etc.
Edit: I see you added the barriers. Sneaky. :)
- dragontamer 7y agoYes, good point. The obscure details are always hard to remember... that particular example is x86 specific. I probably should edit in the memory barriers. > Edit: I see you added the barriers. Sneaky. :) You reminded me about them. Lol. Thanks for the reminder :-)
- vardump 7y agoHmm... are you sure your unlock barrier is in the right place? ;-) Edit: I see you fixed that too.
- dragontamer 7y agoUhhh... now it is :-) This stuff is always hard...
- vardump 7y agoIf you still wanted to fine tune it a bit further, you could have used a WeakAtomicExchange (?). Performs better on some systems, and a strong one is not required here. On x86, it's of course same.
- dragontamer 7y agoHa! I think I'm finally correct against you :-) "AtomicExchange" is just a swap. It is NOT a compare-and-swap, so there's no Weak vs Strong version. A pure-swap is probably faster to implement than a compare-and-swap in microcode, but I admit that I've never actually tested this theory.
- vardump 7y agoIndeed, oops! Brains in pattern matching mode. :-) Then again, I think XCHG (has implicit atomic LOCK, no need for LOCK prefix) is kinda x86 only thing. > pure-swap is probably faster to implement than a compare-and-swap in microcode, but I admit that I've never actually tested this theory. I don't think there's practical performance difference, because inter-core cache coherency traffic is going to dominate by far.
- e12e 7y agoFor others that are curious, there's an example of lock XCHG spin lock for amd64 here: https://en.m.wikibooks.org/wiki/X86_Assembly/Data_Transfer https://en.m.wikibooks.org/wiki/X86_Assembly/Data_Transfer Ed: well technically x86 I guess - not sure if there's improvements to be made for amd64?
- vardump 7y agoThat example is based on "lock cmpxchg" (x86 compare-and-swap). Not on atomic swap, like what "xchg" based one [0] above does. Someone else [1] also had a good point how "xchg" can cause more contention, because it generates stores. If loads were used for waiting instead, the cache line could have remained in much cheaper shared state on the waiting core. But regardless benchmark on as many system types as you can get your hands on. No matter how well you know the architecture and you read on the internet, real software systems and CPUs are sometimes rather unpredictable beasts. [0]: https://news.ycombinator.com/item?id=20098978 https://news.ycombinator.com/item?id=20098978 [1]: https://news.ycombinator.com/item?id=20099764 https://news.ycombinator.com/item?id=20099764
- vardump 7y agoActually, the barriers matter also because evil compilers like to mess with reordering loads and stores. If you write: a = 5; b = 4; ... without any barriers compiler can actually generate code that performs "b = 4" first. Even if the barriers get compiled into nothing, they can still affect the generated code load/store order. I know you know this, but just to make sure even those people reading this later who think their software is only going to run on x86 ever need to watch out. I think std::atomic / std::memory_order are pretty useful abstractions to get these things right.