Sobes.tech
Junior

Co je to deadlock?

sobes.tech AI

Odpověď od AI

Deadlock je situace slepé uličky v multithreadovém programování, kdy dva nebo více vláken blokují navzájem, čekajíce na zdroje, které jsou obsazeny jinými vlákny ve stejné skupině.

Podmínky vzniku deadlocku (Koffmanovy podmínky):

  1. Vzájemné vyloučení (Mutual Exclusion): Zdroje nemohou být používány současně více vlákny.
  2. Držení a čekání (Hold and Wait): Vlákna, která již mají jeden zdroj, čekají na získání dalšího zdroje, který je obsazen jiným vláknem.
  3. Žádné předběhnutí (No Preemption): Zdroj nemůže být vynuceně odebrán vláknu, které jím disponuje; může být uvolněn pouze samotným vláknem.
  4. Kruhové čekání (Circular Wait): Existuje řetězec dvou nebo více vláken, kde každé vlákno čeká na zdroj, který vlastní následující vlákno v řetězci (v podstatě čekání "v kruhu").

Jednoduchý příklad deadlocku:

Dvě vlákna, dva zdroje (A a B).

  • Vlákno 1 získá zdroj A.
  • Vlákno 2 získá zdroj B.
  • Vlákno 1 se pokusí získat zdroj B (který je obsazen Vlákem 2).
  • Vlákno 2 se pokusí získat zdroj A (který je obsazen Vlákem 1).

Obě vlákna jsou navždy zablokována.

// Jednoduchá simulace deadlocku s použitím lock
object resourceA = new object();
object resourceB = new object();

void Thread1Method()
{
    lock (resourceA) // Vlákno 1 získalo A
    {
        Console.WriteLine("Vlákno 1 získalo zdroj A");
        Thread.Sleep(100); // Malé zpoždění pro demonstraci možnosti přepínání vláken
        lock (resourceB) // Vlákno 1 se pokusí získat B
        {
            Console.WriteLine("Vlákno 1 získalo zdroj B");
        }
    }
}

void Thread2Method()
{
    lock (resourceB) // Vlákno 2 získalo B
    {
        Console.WriteLine("Vlákno 2 získalo zdroj B");
        Thread.Sleep(100); // Malé zpoždění
        lock (resourceA) // Vlákno 2 se pokusí získat A
        {
            Console.WriteLine("Vlákno 2 získalo zdroj A");
        }
    }
}

// Vytvoření a spuštění vláken může vést k deadlocku.
// new Thread(Thread1Method).Start();
// new Thread(Thread2Method).Start();

// Spuštění tohoto kódu může, ale nemusí, demonstrovat deadlock,
// protože pořadí provádění závisí na plánovači.
// Pokud vlákno 1 získá A a vlákno 2 získá B dříve, než první
// stihne získat B, vznikne deadlock.

Prevence deadlocků se často dosahuje:

  • Uspořádáním získávání zdrojů (vždy získávat zdroje ve stejném pořadí).
  • Použitím metod získávání s časovým limitem (pokusit se získat zdroj během určitého času).
  • Navržením bez nutnosti držet více zámků současně.
  • Použitím atomárních operací nebo vyšších synchronizačních primitivů (například Monitor.TryEnter, ReaderWriterLockSlim).

Deadlocky jsou obtížné ladit, protože závisí na pořadí provádění vláken a často se projevují pouze při zátěži. Visual Studio nabízí nástroje pro jejich detekci a analýzu.