Sobes.tech
Junior

O que é um deadlock?

sobes.tech IA

Resposta da IA

Um deadlock é uma situação sem saída na programação multithread, onde dois ou mais threads bloqueiam-se mutuamente, esperando recursos que estão sendo utilizados por outros threads do mesmo grupo.

Condições para ocorrer um deadlock (condições de Coffman):

  1. Exclusão mútua (Mutual Exclusion): Os recursos não podem ser utilizados simultaneamente por vários threads.
  2. Retenção e espera (Hold and Wait): Os threads que já possuem um recurso esperam por obter outro recurso que está sendo utilizado por outro thread.
  3. Sem preempção (No Preemption): Um recurso não pode ser forçadamente retirado de um thread que o possui; só pode ser liberado pelo próprio thread.
  4. Espera circular (Circular Wait): Existe uma cadeia de dois ou mais threads onde cada um espera um recurso que é possuído pelo próximo na cadeia (espera em círculo).

Exemplo simples de deadlock:

Dois threads, dois recursos (A e B).

  • O thread 1 captura o recurso A.
  • O thread 2 captura o recurso B.
  • O thread 1 tenta capturar B (que está ocupado pelo thread 2).
  • O thread 2 tenta capturar A (que está ocupado pelo thread 1).

Ambos os threads estão bloqueados para sempre.

// Exemplo simples de simulação de deadlock usando lock
object resourceA = new object();
object resourceB = new object();

void Thread1Method()
{
    lock (resourceA) // Thread 1 captura A
    {
        Console.WriteLine("Thread 1 capturou o recurso A");
        Thread.Sleep(100); // Pequena pausa para demonstrar a possibilidade de troca de threads
        lock (resourceB) // Thread 1 tenta capturar B
        {
            Console.WriteLine("Thread 1 capturou o recurso B");
        }
    }
}

void Thread2Method()
{
    lock (resourceB) // Thread 2 captura B
    {
        Console.WriteLine("Thread 2 capturou o recurso B");
        Thread.Sleep(100); // Pequena pausa
        lock (resourceA) // Thread 2 tenta capturar A
        {
            Console.WriteLine("Thread 2 capturou o recurso A");
        }
    }
}

// A criação e execução de threads podem levar a um deadlock.
// new Thread(Thread1Method).Start();
// new Thread(Thread2Method).Start();

// Executar este código pode, mas não necessariamente, demonstrar um deadlock,
// pois a ordem de execução depende do agendador.
// Se o Thread 1 capturar A e o Thread 2 capturar B antes do primeiro
// conseguir capturar B, ocorrerá um deadlock.

Prevenir deadlocks geralmente é feito por:

  • Ordenar a aquisição de recursos (sempre adquirir os recursos na mesma ordem).
  • Usar métodos de aquisição com timeout (tentar adquirir o recurso por um tempo determinado).
  • Projetar sem necessidade de manter múltiplos bloqueios simultaneamente.
  • Usar operações atômicas ou primitivas de sincronização de nível superior (por exemplo, Monitor.TryEnter, ReaderWriterLockSlim).

Deadlocks são difíceis de depurar, pois dependem da ordem de execução dos threads e muitas vezes só se manifestam sob carga. O Visual Studio fornece ferramentas para detectá-los e analisá-los.