Implementação de Seções Críticas com Monitor em C#

Conceito do Monitor

Conforme documentação da Microsoft, o Monitor previne execução simultânea de blocos de código por múltiplas threads. O método Enter permite que apenas uma thread prossiga, bloqueando outras até que Exit seja chamado. A palavra-chave lock é implementada usando a classe Monitor:


lock(objeto)
{
    ExecutarAcao();
}

Equivalente a:


object obj = (object)objeto;
Monitor.Enter(obj);
try
{
    ExecutarAcao();
}
finally
{
    Monitor.Exit(obj);
}

Prefira lock por sua concisão e garantia de liberação do monitor mesmo em exceções via bloco finally.

Métodos do Monitor

A classe estática Monitor oferece métodos para controle de seções críticas:

  • Enter/TryEnter: Obtém bloqueio de objeto (sempre use tipos por referência). TryEnter não bloqueia, retornando false se o bloqueio falhar
  • Exit: Libera o bloqueio. Sempre execute em finally para evitar deadlokcs

Sincronização Avançada com Wait e Pulse

Considere o cenário produtor-consumidor com buffer compartilhado:


class ExemploProdutorConsumidor
{
    private Queue<string> _buffer = new Queue<string>(1);
    private volatile bool _finalizar = false;

    public void Produzir()
    {
        while (!_finalizar)
        {
            Monitor.Enter(_buffer);
            try
            {
                if (_buffer.Count == 0)
                {
                    _buffer.Enqueue("Dado");
                    Monitor.Pulse(_buffer);
                    Monitor.Wait(_buffer);
                }
                else
                {
                    Monitor.Pulse(_buffer);
                    Monitor.Wait(_buffer);
                }
            }
            finally
            {
                Monitor.Exit(_buffer);
            }
            Thread.Sleep(1000);
        }
    }

    public void Consumir()
    {
        while (!_finalizar || _buffer.Count > 0)
        {
            Monitor.Enter(_buffer);
            try
            {
                if (_buffer.Count > 0)
                {
                    _buffer.Dequeue();
                    Monitor.Pulse(_buffer);
                    Monitor.Wait(_buffer);
                }
                else
                {
                    Monitor.Pulse(_buffer);
                    Monitor.Wait(_buffer);
                }
            }
            finally
            {
                Monitor.Exit(_buffer);
            }
            Thread.Sleep(1000);
        }
    }
}

Métodos essenciais:

  • Wait: Libera o bloqueio e suspende a thread até receber Pulse
  • Pulse: Acorda a primeira thread em espera na fila de bloqueio
  • PulseAll: Acorda todas as threads bloqueadas no objeto

Chame estes métodos apenas dentro de seções críticas. O exemplo demonstra coordenação eficiente onde threads se bloqueiam ativamente ao invés de tentativas repetidas.

Tags: C# threading Monitor Sincronização SeçãoCrítica

Publicado em 7-10 22:37