Spin lock nebo spinlock ( anglicky spinlock - cyclic lock) je nízkoúrovňové synchronizační primitivum [1] používané ve víceprocesorových systémech k implementaci vzájemného vyloučení provádění kritických sekcí kódu pomocí aktivní čekací smyčky [2] . Používá se v případech, kdy se očekává, že čekání na zámek bude krátké [2] nebo pokud kontext provádění neumožňuje přechod do zablokovaného stavu [3] .
Spinlocky jsou podobné mutexům , což vám umožňuje strávit méně času blokováním vlákna, protože nemusíte vlákno převádět do blokovaného stavu. V případě mutexů může být nutné vyvolat plánovač, aby změnil stav vlákna a přidal jej do seznamu vláken čekajících na odemčení. Spinlocky nepoužívají plánovač a používají čekací smyčku bez změny stavu vlákna, což plýtvá časem CPU čekáním na další vlákno, které uvolní zámek. Typickou implementací spinlocku je jednoduchá cyklická kontrola dostupnosti proměnné spinlock [1] .
Fyzicky je spinlock proměnná v paměti a je implementován na atomických operacích , které musí být přítomny v instrukční sadě procesoru . Každý procesor, který chce přistupovat ke sdílenému prostředku atomicky, zapíše do této proměnné podmíněnou hodnotu " busy " pomocí analogu operace swap (v architektuře x86 - xchg). Pokud byla předchozí hodnota proměnné (vrácená příkazem) „ volná “, pak se má za to, že daný procesor přistoupil ke zdroji, jinak se procesor vrátí do swapovací operace a prochází spinlockem, dokud není uvolněn. Po práci se sdíleným prostředkem do něj musí procesor – vlastník spinlocku zapsat podmíněnou hodnotu „ free “.
Příklad implementace spinlocku v x86 assembleru:
mov eax , spinlock_address mov ebx , SPINLOCK_BUSY wait_cycle: xchg [ eax ], ebx ; xchg je jediná instrukce, která je atomická bez předpony lock cmp ebx , SPINLOCK_FREE jnz wait_cycle ; <kritická sekce je zachycena tímto vláknem, zde probíhá práce se sdíleným zdrojem> mov eax , spinlock_address mov ebx , SPINLOCK_FREE xchg [ eax ], ebx ; použijte xchg pro atomovou změnu ; poslední 3 instrukce by měly být nahrazeny mov [spinlock_address], SPINLOCK_FREE - ; tím se zvýší rychlost kvůli absenci zbytečného blokování sběrnice a mov se stejně bude provádět atomicky ; (ale pouze v případě, že spinlock_address je zarovnán na hranici dword)Chytřejší implementace by používala běžnou operaci spíše než atomovou operaci pro dotazování ve smyčce a atomovou operaci pouze pro pokusy o zachycení. Faktem je, že k implementaci operací atomové paměti dochází hardwarovým blokováním systémové sběrnice procesorem po dobu atomické operace (což zahrnuje čtení, úpravy a zápis). Během těchto tří operací nelze na sběrnici provádět žádné další operace, což snižuje výkon ostatních procesorů v systému (pokud sdílejí společnou sběrnici ), i když s tímto spinlockem nemají nic společného.
Používají se také tzv. queued spinlocks - "queued spinlocks". Namísto přiřazení 0 nebo 1 atomové proměnné používají atomické přidání struktury do hlavičky seznamu, zatímco hlavička seznamu je atomická proměnná typu „ukazatel“.
Užitečné vlastnosti spinlocků ve frontě:
Spinlocky se používají k synchronizaci malých částí kódu, když je použití složitějších mechanismů nerozumné nebo nemožné. Implementace synchronizačních primitiv a správce vláken nutně vyžaduje zámky k ochraně seznamů vláken, která jsou připravena ke spuštění, a seznamů vláken, která čekají na objekty. Takový zámek může být pouze spinlock kvůli jeho velmi nízké úrovni. Spinlock je tedy nejnižší synchronizační primitiv, na kterém je založena implementace všech ostatních.
Verze Windows od Windows 7 včetně používají paradigma bez uzamčení datových struktur k implementaci dispečera/plánovače. Jsou tedy ušetřeni jediného globálního spinlocku KiDispatcherLock, jednoho z nejvíce zatížených v jádře OS.
Je rozšířený názor, že v uživatelských aplikacích běžících pod multitaskingovým OS je použití spinlocků nepřijatelné, protože čekání na uvolnění spinlocku vede k aktivnímu čekání ve smyčce, která plýtvá výpočetními prostředky CPU, a musí být použita primitiva na vysoké úrovni. používá se k synchronizaci uživatelských programů, které znamenají pasivní čekání – pokud dané vlákno nemůže pokračovat ve vykonávání, pak dává řízení OS a netočí se v čekací smyčce spinlock (která může být potenciálně nekonečná). Ve skutečnosti je toto tvrzení 100% pravdivé pouze pro jednoprocesorové systémy. V mnoha případech vede použití spinlocků v SMP konfiguracích ke zvýšení efektivity, pokud je dotazování a získávání spinlocku rychlejší než volání akvizice mutexu v jádře.
Hlavním kritériem je zde spor – „rigidita“ soutěže o zdroj. Málo zatížený prostředek, který není oblíbeným místem provádění, se chová jinak než silně zatížený prostředek, který je zachycován a uvolněn velmi často.
Kromě toho ve stejných Windows existují různé mutexy (například známý CRITICAL_SECTION/EnterCriticalSection/LeaveCriticalSection nebo jeho synonymum v jádře OS - FAST_MUTEX/ExAcquireFastMutex/ExReleaseFastMutex), které nejprve fungují jako spinlock pomocí hodnotový dotaz v paměti a teprve poté, po velkém počtu dotazování, přejděte do jádra na blokování čekání. Takové objekty kombinují nejlepší vlastnosti spinlocků (minimální náklady na zachycení) a mutexů (žádné plýtvání prostředky CPU pro dotazování).
Případy, kdy použití spinlocků v uživatelském prostoru dává hmatatelný efekt:
Nicméně použití "rychlých mutexů", jako je CRITICAL_SECTION Win32, činí všechny výše uvedené v uživatelském prostoru zbytečné.
Případy, kdy použití spinlocků není oprávněné a je plýtváním zdrojů procesoru:
U moderních procesorů může být spánkový cyklus velmi rychlý kvůli zvláštnostem zřetězené architektury, která kromě navíjení nečinných cyklů může vést k intenzivnějšímu zahřívání než při běžném provozu.
Pentium 4 a novější modely procesorů Intel zavedly speciální instrukci assembleru pro vložení do smyčky pauzy ( opcode 0xf3 0x90, podobný rep nop pro kompatibilitu se staršími procesory), která má procesoru dát pokyn, že tento cyklus je čekací smyčka, a umožňuje procesoru podporovat více vláken na stejném jádru a přejít na další vlákno.
Verze Windows od Windows 7 jsou optimalizovány tak, aby běžely jako „host“ na virtuálním počítači a místo pauzy v případech, kdy OS běží jako host, speciální volání „upozorněte hypervizor, že jsme v čekací smyčce“ se používá.
Spinlock s automatickým růstem až do zachycení plnohodnotného mutexu po uplynutí určitého počtu otáček cyklu se používá například v kritických částech Windows pro optimalizaci, která spočívá v absenci volání mutexu při absenci konkurence za zdroj.