Zámek otáčení

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 7. srpna 2022; kontroly vyžadují 3 úpravy .

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] .

Fyzická realizace

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ě:

  • záruka pořadí poskytování v pořadí žádosti, záruka proti "hladovění"
  • ve smyčce dotazů se každý procesor dotazuje na svou lokální proměnnou
  • přesně 1 atomová operace při zachycení a přesně 1 při uvolnění

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.

Specifika multiprocesorových a jednoprocesorových konfigurací

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í).

Použití spinlocků

Případy, kdy použití spinlocků v uživatelském prostoru dává hmatatelný efekt:

  • Uvnitř sekce chráněného kódu je několik přidružených proměnných, jejichž doba modifikace může být stokrát i tisíckrát kratší než přepínání kontextu procesorem, což je zvláště na moderních systémech obzvláště nákladná operace.
  • Blokování ne sekcí kódu , ale dat (s každou datovou strukturou, která musí být atomicky změněna jako celek, je spojen spinlock, který ji chrání)
  • Optimalizace kódu, když je potřeba snížit zátěž, ke které dochází v důsledku příliš častého přepínání kontextu

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:

  • Dlouhé operace blokování uvnitř sekce chráněného kódu (vstupy/výstupy disku a sítě mohou podle standardů procesoru trvat velmi dlouho)
  • Konfigurace s jedním procesorem – procesor stráví zbytek času v cyklu nečinnosti .

Problémy se spinlockem a metody jejich řešení

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á.

Alternativy k spinlockům

  • Spinlocks se používají k zajištění toho, že vlákno má výhradní přístup k chráněné datové struktuře. Nerozlišuje mezi samotnými vlákny ani mezi prováděnými operacemi. Často však v reálných aplikacích lze vlákna rozdělit na „čtenáře“ a „zapisovatele“. Pro tento asymetrický případ je vhodnější použít zámky čtení a zápisu . Strukturu může současně používat neomezený počet vláken v režimu „pouze pro čtení“ a zároveň poskytuje ochranu integrity dat, když přijde vlákno pro „zápis“.
  • Existují také algoritmy bez blokování založené na detekci atomových kolizí. Jsou optimalizovány pro optimistický případ, kdy je celá kontrola kolize zredukována na jednu operaci atomického assembleru ( Porovnat a vyměnit , na architektuře x86 - příkaz cmpxchg )

Další modifikace spinlocků

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.

Poznámky

  1. ↑ 1 2 IEEE, The Open Group. Zdůvodnění systémových rozhraní , obecné informace  . The Open Group Base Specifications, vydání 7, 2018 vydání . Otevřená skupina (2018). Získáno 20. června 2020. Archivováno z originálu dne 18. června 2020.
  2. 1 2 Tanenbaum, 2011 , 2.3.3. Active Wait Mutual, Strict Interleaving, str. 156.
  3. Oleg Tsilyurik. Nástroje pro programování jádra: Část 73. Paralelnost a synchronizace. Zámky. Část 1 . - www.ibm.com, 2013. - 13. srpna. — Datum přístupu: 6. 12. 2019.

Literatura

  • M. Russinovič , D. Solomon. 1 // Interní informace systému Microsoft Windows. - 6. vyd. - Petrohrad. : Petr, 2013. - S. 218-222. — 800 s. - ("Mistrovská třída"). — ISBN 978-5-459-01730-4 .
  • Walter Oni. Použití modelu ovladače Microsoft Windows . - 2. vyd. - Petrohrad. : Peter, 2007. - S.  173 -178. — 764 s. - ISBN 978-5-91180-057-4 .
  • Andrew S. Tanenbaum. Moderní operační systémy  = Moderní operační systémy. — 3. vydání. - Petrohrad: Peter: Nakladatelství "Peter", 2011. - S. 165-170. — 1117 s. — (Klasika informatiky). — ISBN 9785459007572 .

Viz také