Junior
Ce este un deadlock?
sobes.tech AI
Răspuns de la AI
Deadlock-ul este o situație fără ieșire în programarea multi-thread, unde două sau mai multe fire de execuție se blochează reciproc, așteptând resursele ocupate de alte fire din același grup.
Condițiile pentru apariția deadlock-ului (condițiile Coffman):
- Excludere mutuală (Mutual Exclusion): Resursele nu pot fi utilizate simultan de mai multe fire.
- Păstrarea și așteptarea (Hold and Wait): Firele care dețin deja o resursă așteaptă să obțină o altă resursă ocupată de alt fir.
- Fără preemțiune (No Preemption): O resursă nu poate fi luată cu forța de la un fir care o deține; poate fi eliberată doar de către firul însuși.
- Așteptare circulară (Circular Wait): Există o lanț de două sau mai multe fire în care fiecare așteaptă o resursă deținută de următorul din lanț (așteptare circulară).
Un exemplu simplu de deadlock:
Două fire, două resurse (A și B).
- Firul 1 preia resursa A.
- Firul 2 preia resursa B.
- Firul 1 încearcă să preia resursa B (ocupată de Firul 2).
- Firul 2 încearcă să preia resursa A (ocupată de Firul 1).
Ambele fire sunt blocate pentru totdeauna.
// Exemplu simplu de simulare deadlock cu lock
object resourceA = new object();
object resourceB = new object();
void Thread1Method()
{
lock (resourceA) // Firul 1 preia A
{
Console.WriteLine("Firul 1 a preluat resursa A");
Thread.Sleep(100); // Pauză scurtă pentru demonstrarea posibilității de schimbare a firelor
lock (resourceB) // Firul 1 încearcă să preia B
{
Console.WriteLine("Firul 1 a preluat resursa B");
}
}
}
void Thread2Method()
{
lock (resourceB) // Firul 2 preia B
{
Console.WriteLine("Firul 2 a preluat resursa B");
Thread.Sleep(100); // Pauză scurtă
lock (resourceA) // Firul 2 încearcă să preia A
{
Console.WriteLine("Firul 2 a preluat resursa A");
}
}
}
// Crearea și pornirea firelor poate duce la deadlock.
// new Thread(Thread1Method).Start();
// new Thread(Thread2Method).Start();
// Rularea acestui cod poate, dar nu neapărat, să demonstreze un deadlock,
// deoarece ordinea de execuție depinde de scheduler.
// Dacă Firul 1 preia A și Firul 2 preia B înainte ca primul
// să poată prelua B, va apărea un deadlock.
Prevenirea deadlock-urilor se realizează adesea prin:
- Ordinea de achiziție a resurselor (a se achiziționa întotdeauna resursele în aceeași ordine).
- Utilizarea metodelor de achiziție cu timeout (încercarea de a obține resursa într-un anumit interval de timp).
- Proiectarea fără necesitatea de a menține mai multe blocări simultan.
- Utilizarea operațiilor atomice sau a primitive de sincronizare de nivel superior (de exemplu,
Monitor.TryEnter,ReaderWriterLockSlim).
Deadlock-urile sunt dificil de depanat deoarece depind de ordinea de execuție a firelor și apar adesea doar sub sarcină. Visual Studio oferă instrumente pentru detectarea și analiza acestora.