Sobes.tech
Middle+

How to implement a Dictionary without using ConcurrentDictionary?

sobes.tech AI

Answer from AI

To implement a thread-safe Dictionary without using ConcurrentDictionary, you can apply synchronization primitives from the System.Threading namespace.

Main approaches:

  1. Locking the entire dictionary (lock): Wrap all read and write operations in a lock block using the same synchronization object.

    // Object for synchronizing access to the dictionary
    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;
        }
    }
    

    Pros: Simple implementation. Cons: Low performance under high contention, as access to the entire dictionary is blocked even during read operations.

  2. Using ReaderWriterLockSlim: Allows separating locks for read and write operations. Multiple threads can read simultaneously, but only one can write.

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

    Pros: Better performance compared to lock during intensive read operations. Cons: More complex implementation than simple lock.

The choice between these approaches depends on the specific usage of the dictionary, the ratio of read to write operations, and the required performance. ReaderWriterLockSlim is generally preferred for frequent read operations.