[HN Gopher] Spinning around: Please don't - Common problems with...
___________________________________________________________________
Spinning around: Please don't - Common problems with spin locks
Author : bdash
Score : 61 points
Date : 2026-01-28 16:48 UTC (6 hours ago)
(HTM) web link (www.siliceum.com)
(TXT) w3m dump (www.siliceum.com)
| gafferongames wrote:
| Great article! Thanks for posting this.
| CamperBob2 wrote:
| Sheesh. Can something this complicated ever truly be said to
| work?
| nh23423fefe wrote:
| Isn't it the opposite? The complication is evidence of
| function. The simple code doesn't work.
| kelnos wrote:
| That assertion feels suspiciously like a logical fallacy.
| maxbond wrote:
| Not really. If the solution has less complexity than is
| inherent in the problem, it can't possibly work. If the
| solution has complexity equal to or greater than the
| complexity inherent in the problem, it _may_ work. So if
| you see complex code handling many different edge cases,
| you can take that as an indicator the author understood the
| problem. That doesn 't mean they do understand or that the
| solution does work; only that you have more confidence than
| you did initially.
|
| It's a weak signal but the reasoning is sound.
| pyrolistical wrote:
| Everything should be made as simple as possible, but not
| simpler.
|
| Code has a minimum complexity to solve the problem
| bluGill wrote:
| You can limit yourself to the performance of a 1mhz 6502 with
| no OS if you don't like it. Even MSDos on a 8086 with 640K ram
| allows for things that require complexity of this type (not
| spin locks, but the tricks needed to make "terminate stay
| resident" work are evil in a similar way)
| yjftsjthsd-h wrote:
| I don't think that's fair. You can go fast, just not more
| than one task at a time.
| bluGill wrote:
| Modern CPUs (since around 2000) go faster in large part
| because they have multiple cores that can do more than one
| thing in a time. If your program needs to go faster using
| more cores is often your best answer and then you will need
| these tricks. (SIMD or the GPU are also common answers that
| might or might not be better for your problem)
| yjftsjthsd-h wrote:
| Modern CPUs can do 4-5 GHz singled threaded. (Sometimes
| you can even get a higher clock speed by disabling other
| cores.) This somewhat outpaces "a 1mhz 6502" even without
| parallelization.
| bluGill wrote:
| They can, but nobody runs a single process on such CPUs.
| They run some form of OS which implements spinlock,
| mutexes, and all these other complex things.
|
| I suppose someplace someone is running an embedded system
| without an OS on such a processor - but I'd expect they
| are still using extra cores and so have all of the above
| tricks someplace.
| adrr wrote:
| OS kernel runqueue is using a spinlock to schedule everything.
| So it works. Should you ever use a spinlock in application
| code? No. Let the OS via the synchronization primitives in
| whatever language your app is in.
| direwolf20 wrote:
| Yes, if you're careful. Actually careful, not pretend careful.
| Which is pretty normal in C and C++.
| jcranmer wrote:
| The basic rule of writing your own cross-thread datastructures
| like mutexes or condition variables is... don't, unless you have
| very good reason not to. If you're in that rare circumstance
| where you know the library you're using isn't viable for some
| reason, then the next best rule is to use your OS's version of a
| futex as the atomic primitive, since it's going to solve most of
| the pitfalls for you automatically.
|
| The only time I've manually written my own spin lock was when I
| had to coordinate between two different threads, one of which was
| running 16-bit code, so using any library was out of the
| question, and even relying on syscalls was sketchy because making
| sure the 16-bit code is in the right state to call a syscall
| itself is tricky. Although in this case, since I didn't need to
| care about things like fairness (only two threads are involved),
| the spinlock core ended up being simple:
| "thunk_spin:", "xchg cx, es:[{in_rv}]",
| "test cx, cx", "jnz thunk_has_data",
| "pause", "jmp thunk_spin", "thunk_has_data:",
| kccqzy wrote:
| Another time when writing a quick and dirty spinlock is
| reasonable is inside a logging library. A logging library would
| normally use a full-featured mutex, but what if we want the
| mutex implementation to be able to log? Say the mutex can log
| that it is non recursive yet the same thread is acquiring it
| twice; or that it has detected a deadlock. The solution is to
| introduce a special subset of the logging library to use a
| spinlock.
| wizzwizz4 wrote:
| I'm not sure how a spinlock solves this problem. Wouldn't
| that just cause the process to hang busy?
| direwolf20 wrote:
| Only until the other thread leaves the logger
| wizzwizz4 wrote:
| Oh, I see: the spinlock is for logging the deadlocks of
| other mutices, not for magically remediating deadlocks.
| fasterik wrote:
| As always: use standard libraries first, profile, then write
| your own if the data indicate that it's necessary. To your
| point, the standard library probably already uses the OS
| primitives under the hood, which themselves do a short
| userspace spin-wait and then fall back to a kernel wait queue
| on contention. If low latency is a priority, the latter might
| be unacceptable.
|
| The following is an interesting talk where the author used a
| custom spinlock to significantly speed up a real-time physics
| solver.
|
| Dennis Gustafsson - Parallelizing the physics solver - BSC 2025
| https://www.youtube.com/watch?v=Kvsvd67XUKw
| wallstop wrote:
| I wrote my own spin lock library over a decade ago in order to
| learn about multi threading, concurrency, and how all this
| stuff works. I learned a lot!
| jeffbee wrote:
| "Unfair" paragraph is way too short. This is the main problem!
| The outlier starvation you get from contended spinlocks is
| extraordinary and, hypothetically, unbounded.
| tialaramex wrote:
| Well, you need to have specified what you actually want. "Fair"
| sounds like it's just good, but it's expensive, so unless you
| know _that_ you need it, which probably means knowing _why_ ,
| you probably don't want to pay the price.
|
| Stealing is an example of an unfairness which can significantly
| improve overall performance.
| a-dub wrote:
| i always got the sense that spinlocks were about maximum
| portability and reliability in the face of unreliable event
| driven approaches. the dumb inefficient thing that makes the
| heads of the inexperienced explode, but actually just works and
| makes the world go 'round.
| rdtsc wrote:
| > Notice that in the Skylake Client microarchitecture the RDTSC
| instruction counts at the machine's guaranteed P1 frequency
| independently of the current processor clock (see the INVARIANT
| TSC property), and therefore, when running in Intel(r) Turbo-
| Boost-enabled mode, the delay will remain constant, but the
| number of instructions that could have been executed will change.
|
| rdtsc may execute out of order, so sometimes an lfence
| (previously cpuid) can be used and there is also rdtscp
|
| See
| https://github.com/torvalds/linux/blob/master/arch/x86/inclu...
|
| And just because rdtsc is constant doesn't mean the processor
| clock will be constant that could be fluctuating.
| pizlonator wrote:
| TFA lists WebKit as a project that "does it wrong".
|
| The author should read https://webkit.org/blog/6161/locking-in-
| webkit/ so that they understand what they are talking about.
|
| WebKit does it right in the sense that:
|
| - It as an optimal amount of spinning
|
| - Threads wait (instead of spinning) if the lock is not available
| immediately-ish
|
| And we know that the algorithms are optimal based on rigorous
| experiments.
___________________________________________________________________
(page generated 2026-01-28 23:00 UTC)