Spinlock versus mutex: wachten, CPU-gebruik en gebruik in de kernel vergeleken
Spinlocks en mutexen zijn allebei locks die slechts één thread tegelijk in een kritieke sectie toelaten, maar ze wachten op een andere manier tot de lock vrijkomt. Een spinlock wacht met busy waiting, waarbij de lockvariabele in een lus steeds opnieuw wordt gecontroleerd; hij blijft tijdens het wachten CPU-tijd gebruiken, maar kan de lock direct nemen zodra die vrij is. Een mutex laat de wachtende thread slapen en geeft de CPU vrij; zodra de lock wordt vrijgegeven, wekt het besturingssysteem de thread. Spinlocks worden gebruikt bij zeer korte houdtijden en in interrupthandlers die niet mogen slapen, mutexen bij lange houdtijden of als de thread tijdens het vasthouden mogelijk moet slapen.
| Kenmerk | Spinlock | Mutex |
|---|---|---|
| Manier van wachten | Controleert de variabele in een lus tot de lock vrij is (busy waiting) | Slaapt als de lock bezet is en wordt gewekt zodra die wordt vrijgegeven |
| CPU tijdens het wachten | Blijft die gebruiken | Geeft die vrij. Andere threads kunnen de CPU in die tijd gebruiken |
| Overhead van het wachten | Geen contextwissel; de lock wordt direct genomen zodra die vrij is | Bij inslapen en ontwaken kosten systeemaanroepen en contextwissels tijd |
| Geschikte houdtijd | Zeer kort (korter dan de tijd van een contextwissel) | Lang. Wanneer de thread tijdens het vasthouden mogelijk slaapt, bijvoorbeeld bij het wachten op I/O |
| Slapen terwijl de lock wordt vastgehouden | Niet toegestaan. De wachtende kant zou dan CPU-tijd blijven verbruiken | Toegestaan |
| Bij één kern | Tijdens het wachten kan de thread die de lock heeft niet draaien, dus spinnen maakt de lock niet vrij. In de kernel wordt preëmptie uitgeschakeld tijdens het gebruik | Werkt zonder problemen |
| Gebruik in de kernel | Ook bruikbaar waar niet mag worden geslapen, zoals in interrupthandlers (interruptcontext). Bij data die met een interrupt wordt gedeeld, worden eerst interrupts uitgeschakeld en daarna wordt de lock genomen | Kan slapen en is dus alleen in procescontext bruikbaar, niet in interrupthandlers |
| Prioriteitsinversie | Als de thread die de lock heeft wordt onderbroken, blijft de wachtende kant spinnen. De kernel voorkomt dit door preëmptie tijdens het vasthouden uit te schakelen | Te ondervangen met een mutex met prioriteitsovererving |
| Voorbeeld van implementatie | De variabele wordt aangepast met atomaire instructies (test-and-set of compare-and-swap). Test-and-test-and-set wacht normaal met gewone leesacties en vermindert zo het verkeer tussen kernen | Met futex in Linux wordt bij geen concurrentie alleen met atomaire instructies in user space gelockt, en alleen bij concurrentie laat de kernel de thread slapen. Er zijn ook implementaties die eerst even spinnen en dan slapen |
De getalswaarden zijn typische ordegroottes en variëren per procesgeneratie en product.