dedlokTakévzájemné zablokování, zablokování zámkůPokročilý
Definice
Deadlock je stav, kdy se dva nebo více procesů, vláken nebo transakcí navzájem blokují, protože každý drží prostředek, který potřebuje někdo další. Výpočet pak nemůže pokračovat bez zásahu plánovače, databáze nebo aplikace, typicky u zámků, mutexů, souborů či řádků v databázi.
Proč deadlock nevzniká jen pomalostí
Deadlock je logická patová situace, ne jen dlouhé čekání. Program může být jinak správně napsaný, ale dvě části systému si vezmou prostředky v opačném pořadí a žádná už nepustí ten svůj. Typicky jde o zámky v paměti, řádky v databázi, soubory, fronty nebo jiné exkluzivní prostředky.
Pomalejší server, přetížená síť nebo dlouhá transakce mohou vypadat podobně, protože uživatel vidí jen zaseknutou operaci. Rozdíl je v tom, že deadlock se sám nevyřeší běžným doběhnutím práce. Některý účastník musí být přerušen, zámek musí vypršet, nebo musí zasáhnout plánovač či databázový engine.
Čtyři podmínky uváznutí
Klasický popis deadlocku stojí na čtyřech podmínkách. Musí existovat výlučné vlastnictví prostředku, čekání při současném držení jiného prostředku, nemožnost násilně prostředek odebrat a kruhové čekání. Kruhové čekání znamená řetězec typu A čeká na B, B čeká na C a C čeká na A.
První tři podmínky bývají v reálných systémech často žádoucí. Mutex má chránit sdílená data, transakce má držet zámek do potvrzení a operační systém nemůže libovolně vzít procesu rozpracovaný soubor. Praktická prevence se proto nejčastěji zaměřuje na zrušení kruhového čekání, například pevným pořadím zamykání.
Kde se deadlock projeví nejčastěji
Databázový deadlock vzniká, když dvě transakce zamknou různé řádky a pak se pokusí získat řádek držený druhou transakcí. Databáze obvykle umí takový cyklus detekovat a jednu transakci zruší jako oběť. Aplikace musí s touto chybou počítat a bezpečně opakovat celou transakci, ne jen poslední SQL příkaz.
Vícevláknový deadlock se objevuje v programech, které používají více zámků nad sdíleným stavem. Vlákno může držet zámek nad cache a zároveň čekat na zámek konfigurace, zatímco jiné vlákno drží konfiguraci a čeká na cache. Deadlock se liší od race condition: race condition závisí na pořadí souběhu, deadlock vede k trvalému čekání.
Proč pořadí zámků rozhoduje
Praktická obrana proti deadlocku začíná návrhem. Sdílené prostředky je vhodné zamykat vždy ve stejném pořadí, držet zámky co nejkratší dobu a nevolat neznámý externí kód uvnitř kritické sekce. V databázích pomáhá konzistentní pořadí aktualizací, krátké transakce a vhodné indexy, které omezí rozsah zamčených řádků.
Bezpečný systém počítá i s tím, že prevence nebude dokonalá. Databázová aplikace má rozpoznat chybu deadlocku, provést rollback a zopakovat transakci jako jeden celek. Serverový program může používat timeouty, diagnostické výpisy zámků a testy se souběžnou zátěží. Timeout ale není oprava příčiny, pouze zabraňuje nekonečnému čekání.
Příklady z praxe
Dva mutexy v opačném pořadí
Dvě funkce zamykají stejné mutexy v opačném pořadí. Při nevhodném proložení běhu první vlákno drží lock_a a čeká na lock_b, zatímco druhé vlákno drží lock_b a čeká na lock_a. Program se může zastavit bez výjimky, protože obě vlákna jen čekají.
import threading lock_a = threading.Lock() lock_b = threading.Lock() def worker_1(): with lock_a: with lock_b: print("hotovo 1") def worker_2(): with lock_b: with lock_a: print("hotovo 2") threading.Thread(target=worker_1).start() threading.Thread(target=worker_2).start()Převod mezi dvěma účty
Dvě databázové transakce upravují stejné účty, ale každá začne jiným řádkem. První transakce zamkne účet 1 a čeká na účet 2, druhá zamkne účet 2 a čeká na účet 1. Databáze cyklus rozpozná a jednu transakci obvykle zruší, aby druhá mohla pokračovat.
-- Transakce A BEGIN; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; COMMIT; -- Transakce B běží současně BEGIN; UPDATE accounts SET balance = balance - 50 WHERE id = 2; UPDATE accounts SET balance = balance + 50 WHERE id = 1; COMMIT;
Časté omyly
- MýtusDeadlock je jen pomalý dotaz nebo pomalé vlákno.
- Ve skutečnostiDeadlock je cyklus čekání, ve kterém žádná strana nemůže pokračovat bez zásahu. Pomalá operace může skončit sama, deadlock typicky vyžaduje zrušení jedné části práce nebo změnu zamykání.
- MýtusStačí dát zámkům delší timeout a deadlock zmizí.
- Ve skutečnostiDelší timeout pouze oddálí selhání a může zhoršit latenci celé aplikace. Příčina deadlocku zůstává v pořadí zamykání, délce držení zámků nebo v návrhu transakcí.
Časté dotazy
- Jak poznám deadlock v databázi?
- Deadlock v databázi se obvykle projeví chybou transakce, zprávou o detekovaném uváznutí nebo zrušením jednoho dotazu serverem. Aplikační kód by měl takovou chybu zachytit, provést rollback a zopakovat celou transakci. Pouhé opakování posledního příkazu může porušit logiku operace, protože předchozí kroky transakce už byly vráceny.
- Vyřeší deadlock nastavení timeoutu?
- Timeout čekání na zámek zabrání tomu, aby požadavek visel donekonečna, ale timeout sám neodstraňuje kruhovou závislost mezi držiteli zámků. Deadlock může po timeoutu zmizet jen proto, že jedna strana práci vzdala. Správná oprava hledá pořadí zamykání, délku transakcí, rozsah zámků a místa, kde se zámek drží zbytečně dlouho.
- Proč deadlock není totéž co race condition?
- Deadlock a race condition jsou různé chyby souběhu. Deadlock znamená, že účastníci čekají navzájem a výpočet nepokračuje. Race condition znamená, že výsledek závisí na přesném načasování operací, takže program někdy vrátí špatná data nebo poruší invariantu. Zámky mohou race condition opravit, ale špatně navržené zámky mohou zavést deadlock.
- Jak se deadlockům předchází v praxi?
- Deadlock lze často omezit pevným pořadím zamykání prostředků, krátkými kritickými sekcemi a návrhem, který nedrží zámek při síťovém volání nebo čekání na uživatele. V databázích pomáhá aktualizovat tabulky a řádky konzistentně, zkracovat transakce a opakovat transakci po detekovaném uváznutí. Úplné vyloučení bývá obtížné ve velkých distribuovaných systémech.
Zdroje
- Deadlock(otevře se v novém okně)
- Explicit Locking(otevře se v novém okně)
- SQL Server deadlocks guide(otevře se v novém okně)
- Deadlock(otevře se v novém okně)