Sobes.tech
Middle+

Como implementar um Dictionary sem usar ConcurrentDictionary?

sobes.tech IA

Resposta da IA

Para implementar um Dictionary seguro para threads sem usar ConcurrentDictionary, pode-se usar primitivas de sincronização do namespace System.Threading.

Abordagens principais:

  1. Bloqueio de todo o dicionário (lock): Envolver todas as operações de leitura e escrita em um bloco lock usando o mesmo objeto de sincronização.

    // Objeto para sincronizar o acesso ao dicionário
    private readonly object _lockObject = new object();
    private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
    
    public void AddOrUpdate(TKey key, TValue value)
    {
        lock (_lockObject)
        {
            if (_dictionary.ContainsKey(key))
            {
                _dictionary[key] = value;
            }
            else
            {
                _dictionary.Add(key, value);
            }
        }
    }
    
    public bool TryGetValue(TKey key, out TValue value)
    {
        lock (_lockObject)
        {
            return _dictionary.TryGetValue(key, out value);
        }
    }
    
    public bool TryRemove(TKey key, out TValue value)
    {
        lock (_lockObject)
        {
            if (_dictionary.TryGetValue(key, out value))
            {
                _dictionary.Remove(key);
                return true;
            }
            return false;
        }
    }
    

    Vantagens: Implementação simples. Desvantagens: Baixo desempenho em alta concorrência, pois bloqueia o acesso a todo o dicionário mesmo em operações de leitura.

  2. Uso de ReaderWriterLockSlim: Permite separar os bloqueios para operações de leitura e escrita. Vários threads podem ler simultaneamente, mas apenas um pode escrever.

    private readonly ReaderWriterLockSlim _lockSlim = new ReaderWriterLockSlim();
    private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
    
    public void AddOrUpdate(TKey key, TValue value)
    {
        _lockSlim.EnterWriteLock();
        try
        {
            if (_dictionary.ContainsKey(key))
            {
                _dictionary[key] = value;
            }
            else
            {
                _dictionary.Add(key, value);
            }
        }
        finally
        {
            _lockSlim.ExitWriteLock();
        }
    }
    
    public bool TryGetValue(TKey key, out TValue value)
    {
        _lockSlim.EnterReadLock();
        try
        {
            return _dictionary.TryGetValue(key, out value);
        }
        finally
        {
            _lockSlim.ExitReadLock();
        }
    }
    
    public bool TryRemove(TKey key, out TValue value)
    {
        _lockSlim.EnterWriteLock();
        try
        {
            if (_dictionary.TryGetValue(key, out value))
            {
                _dictionary.Remove(key);
                return true;
            }
            return false;
        }
        finally
        {
            _lockSlim.ExitWriteLock();
        }
    }
    

    Vantagens: Melhor desempenho em comparação com lock em operações intensivas de leitura. Desvantagens: Implementação mais complexa do que com um simples lock.

A escolha entre essas abordagens depende da natureza do uso do dicionário, da proporção de operações de leitura e escrita, e dos requisitos de desempenho. ReaderWriterLockSlim costuma ser preferido em operações frequentes de leitura.