线程安全的SortedDictionary

时间:2014-03-10 18:14:29

标签: c# multithreading dictionary wrapper sorteddictionary

我创建了一个使用SortedDictionary来存储和操作数据的类。除非在多线程环境中实现,否则该类很有效。现在,我想通过为内部SortedDictionary类编写包装类来使类线程安全。我想使用Reader-Writer Locks来实现它,但是现在,我在编写包装器本身时遇到了问题。具体来说,我不确定如何为字典实现Enumerator。这是我现在的完整代码。

    public class ConcurrentSortedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    #region Variables
    SortedDictionary<TKey, TValue> _dict;
    #endregion
    #region Constructors
    public ConcurrentSortedDictionary()
    {
        _dict = new SortedDictionary<TKey, TValue>();
    }

    public ConcurrentSortedDictionary(IComparer<TKey> comparer)
    {
        _dict = new SortedDictionary<TKey, TValue>(comparer);
    }

    public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dict = new SortedDictionary<TKey, TValue>(dictionary);
    }

    public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
    {
        _dict = new SortedDictionary<TKey, TValue>(dictionary, comparer);
    }
    #endregion
    #region Properties
    public IComparer<TKey> Comparer
    {
        get 
        { 
            return _dict.Comparer;
        }
    }

    public int Count
    {
        get
        {
            return _dict.Count;
        }
    }

    public TValue this[TKey key]
    { 
        get
        {
            return _dict[key];
        }

        set
        {
            _dict[key] = value;
        }
    }

    public SortedDictionary<TKey, TValue>.KeyCollection Keys
    {
        get
        {
            return new SortedDictionary<TKey,TValue>.KeyCollection(_dict);
        }
    }

    public SortedDictionary<TKey, TValue>.ValueCollection Values
    {
        get
        {
            return new SortedDictionary<TKey, TValue>.ValueCollection(_dict);
        }
    }

    #endregion
    #region Methods
    public void Add(TKey key, TValue value)
    {
        _dict.Add(key, value);
    }

    public void Clear()
    {
        _dict.Clear();
    }

    public bool ContainsKey(TKey key)
    {
        return _dict.ContainsKey(key);
    }

    public bool ContainsValue(TValue value)
    {
        return _dict.ContainsValue(value);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
    {
        _dict.CopyTo(array, index);
    }

    public override bool Equals(Object obj)
    {
        return _dict.Equals(obj);
    }

    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dict.GetEnumerator();
    }

    public override int GetHashCode()
    {
        return _dict.GetHashCode();
    }

    public bool Remove(TKey key)
    {
        return _dict.Remove(key);
    }

    public override string ToString()
    {
        return _dict.ToString();
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _dict.TryGetValue(key, out value);
    }
    #endregion
}

编译代码时,收到错误消息:

  

'ConcurrentSortedDictionary'没有实现接口   member'System.Collections.IEnumerable.GetEnumerator()'。   'ConcurrentSortedDictionary.GetEnumerator()'不能   实现'System.Collections.IEnumerable.GetEnumerator()'因为它   没有匹配的返回类型   'System.Collections.IEnumerator'。

我在这里看了几篇与此相关的帖子作为参考:

How do I implement IEnumerable in my Dictionary wrapper class that implements IEnumerable<Foo>? What's the best way of implementing a thread-safe Dictionary?

但我不明白我做错了什么。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

问题在于:

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
    return GetEnumerator();
}

public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
    return _dict.GetEnumerator();
}

你需要:

public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
    return _dict.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
    return _dict.GetEnumerator();
}

第二个非泛型GetEnumerator()是一个explicit interface implementation,需要作为C#中存在泛型和泛型集合之前的不幸回归。

另请参阅:IEnumerable<T> provides two GetEnumerator methods - what is the difference between them?(特别是Michael B's answer)。

但是如果您希望枚举与其他类一起是线程安全的,您可能还需要编写自己的线程安全IEnumerator类型,它与读者合作/作家锁在你的班级!

答案 1 :(得分:1)

在实施dvnrrs的建议之后,我现在让班级运作良好。我甚至为IEnumerable接口添加了一个包装类来保护SortedDictionary的枚举(这里的代码修改的代码如下:http://www.codeproject.com/Articles/56575/Thread-safe-enumeration-in-C)。以下是包含Reader-Writer Locks的更新代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;

public class SafeEnumerator<T> : IEnumerator<T>
{
    #region Variables

    // this is the (thread-unsafe)
    // enumerator of the underlying collection
    private readonly IEnumerator<T> _enumerator;

    // this is the object we shall lock on. 
    private ReaderWriterLockSlim _lock;

    #endregion 

    #region Constructor

    public SafeEnumerator(IEnumerator<T> inner, ReaderWriterLockSlim readWriteLock)
    {
        _enumerator = inner;
        _lock = readWriteLock;

        // Enter lock in constructor
        _lock.EnterReadLock();
    }

    #endregion

    #region Implementation of IDisposable

    public void Dispose()
    {
        // .. and exiting lock on Dispose()
        // This will be called when the foreach loop finishes
        _lock.ExitReadLock();
    }

    #endregion

    #region Implementation of IEnumerator

    // we just delegate actual implementation
    // to the inner enumerator, that actually iterates
    // over some collection

    public bool MoveNext()
    {
        return _enumerator.MoveNext();
    }

    public void Reset()
    {
        _enumerator.Reset();
    }

    public T Current
    {
        get 
        { 
            return _enumerator.Current; 
        }
    }

    object IEnumerator.Current
    {
        get 
        { 
            return Current; 
        }
    }

    #endregion
}

public class ConcurrentSortedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    #region Variables

    private ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();
    SortedDictionary<TKey, TValue> _dict;

    #endregion

    #region Constructors

    public ConcurrentSortedDictionary()
    {
        _dict = new SortedDictionary<TKey, TValue>();
    }

    public ConcurrentSortedDictionary(IComparer<TKey> comparer)
    {
        _dict = new SortedDictionary<TKey, TValue>(comparer);
    }

    public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dict = new SortedDictionary<TKey, TValue>(dictionary);
    }

    public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
    {
        _dict = new SortedDictionary<TKey, TValue>(dictionary, comparer);
    }

    #endregion

    #region Properties

    public IComparer<TKey> Comparer
    {
        get 
        {
            _readWriteLock.EnterReadLock();
            try
            {
                return _dict.Comparer;
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
    }

    public int Count
    {
        get
        {
            _readWriteLock.EnterReadLock();
            try
            {
                return _dict.Count;
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
    }

    public TValue this[TKey key]
    { 
        get
        {
            _readWriteLock.EnterReadLock();
            try
            {
                return _dict[key];
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
        set
        {
            _readWriteLock.EnterWriteLock();
            try
            {
                _dict[key] = value;
            }
            finally
            {
                _readWriteLock.ExitWriteLock();
            }
        }
    }

    public SortedDictionary<TKey, TValue>.KeyCollection Keys
    {
        get
        {
            _readWriteLock.EnterReadLock();
            try
            {
                return new SortedDictionary<TKey, TValue>.KeyCollection(_dict);
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
    }

    public SortedDictionary<TKey, TValue>.ValueCollection Values
    {
        get
        {
            _readWriteLock.EnterReadLock();
            try
            {
                return new SortedDictionary<TKey, TValue>.ValueCollection(_dict);
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
    }

    #endregion

    #region Methods

    public void Add(TKey key, TValue value)
    {
        _readWriteLock.EnterWriteLock();
        try
        {
            _dict.Add(key, value);
        }
        finally
        {
            _readWriteLock.ExitWriteLock();
        }
    }

    public void Clear()
    {
        _readWriteLock.EnterWriteLock();
        try
        {
            _dict.Clear();
        }
        finally
        {
            _readWriteLock.ExitWriteLock();
        }
    }

    public bool ContainsKey(TKey key)
    {
        _readWriteLock.EnterReadLock();
        try
        {
            return _dict.ContainsKey(key);
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    public bool ContainsValue(TValue value)
    {
        _readWriteLock.EnterReadLock();
        try
        {
            return _dict.ContainsValue(value);
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
    {
        _readWriteLock.EnterReadLock();
        try
        {
            _dict.CopyTo(array, index);
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    public override bool Equals(Object obj)
    {
        _readWriteLock.EnterReadLock();
        try
        {
            return _dict.Equals(obj);
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return new SafeEnumerator<KeyValuePair<TKey, TValue>>(_dict.GetEnumerator(), _readWriteLock);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return new SafeEnumerator<KeyValuePair<TKey, TValue>>(_dict.GetEnumerator(), _readWriteLock);
    }

    public override int GetHashCode()
    {
        _readWriteLock.EnterReadLock();
        try
        {
            return _dict.GetHashCode();
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    public bool Remove(TKey key)
    {
        _readWriteLock.EnterWriteLock();
        try
        {
            return _dict.Remove(key);
        }
        finally
        {
            _readWriteLock.ExitWriteLock();
        }
    }

    public override string ToString()
    {
        _readWriteLock.EnterReadLock();
        try
        {
            return _dict.ToString();
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        _readWriteLock.EnterReadLock();
        try
        {
            return _dict.TryGetValue(key, out value);
        }
        finally
        {
            _readWriteLock.ExitReadLock();
        }
    }

    #endregion
}