Sobes.tech
Middle+

Come implementare un Dictionary senza usare ConcurrentDictionary?

sobes.tech AI

Risposta dell'AI

Per implementare un Dictionary thread-safe senza usare ConcurrentDictionary, puoi utilizzare primitive di sincronizzazione dello spazio dei nomi System.Threading.

Approcci principali:

  1. Bloccare l'intero dizionario (lock): Avvolgere tutte le operazioni di lettura e scrittura in un blocco lock usando lo stesso oggetto di sincronizzazione.

    // Oggetto per sincronizzare l'accesso al dizionario
    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;
        }
    }
    

    Vantaggi: Implementazione semplice. Svantaggi: Bassa performance in alta concorrenza, poiché si blocca l'accesso a tutto il dizionario anche durante le operazioni di lettura.

  2. Utilizzo di ReaderWriterLockSlim: Permette di separare i blocchi per operazioni di lettura e scrittura. Più thread possono leggere contemporaneamente, ma solo uno può scrivere.

    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();
        }
    }
    

    Vantaggi: Migliore performance rispetto a lock in operazioni di lettura intensive. Svantaggi: Implementazione più complessa rispetto a un semplice lock.

La scelta tra questi approcci dipende dalle caratteristiche dell'uso del dizionario, dalla proporzione di operazioni di lettura e scrittura e dai requisiti di performance. ReaderWriterLockSlim è generalmente preferibile per operazioni di lettura frequenti.