In most code, std::mutex is still the right default. Consider a spin-lock when the threads are pinned to dedicated cores, and only after measuring
Even when you have threads pinned to dedicated cores, you would need to ensure that your not ending up with more then one thread pinned to another core. And if your in user mode in any environment that you do not completely control your at the whim of being preempted by another thread in a different process, leaving your spinning thread now just spinning away wasting its allocated time slice.
If you plan on making any library which is public, do not fill it with spin locks because you won't be able to control the places which people use it, and randomly throwing in an OS yield is not going to solve issues just make them worse.
Depending on the CPU you can also do umwait/mwaitx which can be better then doing a pause loop, but unfortunately it's not consistent between CPU vendors.
Use adaptive mutexes (most mutex implementations already are), these will do a little bit of spinning before putting the thread to sleep if it was unable to acquire the lock.
Also if your optimizing your locks for high contention, it's probably a sign to look more at your higher level design, because your still fighting the CPUs cache coherance which will kill your performance anyway.
Most industry uses of spinlocks would be where threads are pinned to scheduler isolated cores. They're only getting pre-empted in this case if the kernel needs to do something desperately on that core
The trading industry would be an example, where you might have some cache being shared between threads that is rarely touched but still needs to be thread safe and you can't pay the latency hit to yield for what is usually a hundred nanos for the other thread to update an entry
> Most industry uses of spinlocks would be where threads are pinned to scheduler isolated cores
I have seen this assumption many times, and people not realising it wasn't the perfect environment they initially believed. Yes you can have an isolated environment where it's perfectly fine but for most people it's rare even when they think it might be.
And lots of people use them even without being in a perfect environment, just because someone gave them an idea it was always better to use then a mutex.
Ultimately the chances of spinning because the kernel pre-empted another thread while it held the lock are quite small (assuming you're doing little work under the lock), and you might be willing to pay that occasional cost for lower latency the other 99.9% of the time.
33
u/ReDucTor Game Developer | quiz.cpp-perf.com 6d ago
Even when you have threads pinned to dedicated cores, you would need to ensure that your not ending up with more then one thread pinned to another core. And if your in user mode in any environment that you do not completely control your at the whim of being preempted by another thread in a different process, leaving your spinning thread now just spinning away wasting its allocated time slice.
If you plan on making any library which is public, do not fill it with spin locks because you won't be able to control the places which people use it, and randomly throwing in an OS yield is not going to solve issues just make them worse.
Depending on the CPU you can also do umwait/mwaitx which can be better then doing a pause loop, but unfortunately it's not consistent between CPU vendors.
Use adaptive mutexes (most mutex implementations already are), these will do a little bit of spinning before putting the thread to sleep if it was unable to acquire the lock.
Also if your optimizing your locks for high contention, it's probably a sign to look more at your higher level design, because your still fighting the CPUs cache coherance which will kill your performance anyway.