Sobes.tech
Middle+

Como é que se trabalha com threads e tarefas quando vários deles acedem a um estado comum?

sobes.tech IA

Resposta da IA

Para aceder de forma segura ao estado compartilhado num ambiente multithread, utilizam-se mecanismos de sincronização.

Abordagens principais:

  • Bloqueios: lock é o mecanismo mais comum. Garante acesso exclusivo a um bloco de código ou objeto por um único thread de cada vez. Mutex (exclusão mútua) também é utilizado, mas frequentemente na interação entre processos.
  • Semânticas: Limitam o número de threads que podem aceder a um recurso simultaneamente.
  • Monitor: Representa uma versão mais poderosa de lock, permitindo que threads aguardem notificações de outros threads.
  • ReadWriteLock: Permite que múltiplos threads leiam dados de forma concorrente, mas apenas um pode escrever.
  • Operações atómicas: Para operações simples (incremento, decremento, comparação-troca), podem-se usar métodos estáticos da classe Interlocked.

Ao trabalhar com tarefas (Tasks), especialmente usando async/await, é importante lembrar que as tarefas não estão vinculadas a um thread específico. Os contextos de sincronização (SynchronizationContext) ajudam a regressar ao contexto necessário (por exemplo, o thread de UI) após a conclusão de uma operação assíncrona.

Exemplo de uso de lock:

// Objeto para bloqueio
private readonly object _lockObject = new object();
private int _sharedCounter = 0;

public void IncrementCounter()
{
    // Bloqueia o acesso ao contador compartilhado
    lock (_lockObject)
    {
        _sharedCounter++;
    }
}

Exemplo de uso de Interlocked:

private int _sharedAtomicCounter = 0;

public void IncrementAtomicCounter()
{
    // Incremento atómico
    Interlocked.Increment(ref _sharedAtomicCounter);
}