日期:2014-05-20  浏览次数:20907 次

请教自定义Dictionary类如何在类内实现线程同步的问题谢谢!
微软的Dictionary的实例成员是不支持线程安全的,因此我自定义了一个Dictionary,但在进行枚举操作的时候无法进行锁定,请大家帮帮我想想办法,代码如下:
C# code

 public class DictionaryEx<Tkey, Tvalue>
    {
        public DictionaryEx()
        {
            mDic = new Dictionary<Tkey, Tvalue>();
        }

        private Dictionary<Tkey, Tvalue> mDic;

        public void Add(Tkey Key, Tvalue Item)
        {
            ICollection ic = mDic.Values;
            lock (ic.SyncRoot)
            {mDic.Add(Key, Item); }
            

        }

        public Dictionary<Tkey, Tvalue>.Enumerator GetEnumerator()
        {
            ICollection ic = mDic.Values;
            lock (ic.SyncRoot)//这一句根本起不了作用
            { return mDic.GetEnumerator(); }
        }

        public Dictionary<Tkey, Tvalue>.ValueCollection Values
        {
            get { return mDic.Values; }

        }
    }



------解决方案--------------------
关注 
目前我知道的方法就是某人说的副本方式
------解决方案--------------------
http://devplanet.com/blogs/brianr/archive/2008/09/26/thread-safe-dictionary-in-net.aspx
------解决方案--------------------
关于枚举,如果你加锁,那效率太低了,别的线程一定要等你枚举完了,才能访问。往往我们做枚举不一定非到要得到最精确的数据。你可以先获取它的所有keys,然后遍历keys去访问里面的数据。

下面是本人写的一个县城安全的dictionary,供参考,请注意我有一个AllKeys的属性,这个就是获取所有keys,然后外面的程序从这个属性获取的数据去遍历就可以了,之所以加上一个keysisnew,是因为如果数据量大,Keys.ToArray()也会耗费较长时间,所以只有发生项的添加和减少时,才会重新生成keys集合。

C# code

    public class SynchronizedDictionary<TKey, TValue>
    {
        private readonly object _syncRoot = new object();
        private readonly Dictionary<TKey, TValue> _dictionaryBase;
        TKey[] _allKeys = new TKey[0];
        bool _keysIsNew = false;
        public SynchronizedDictionary()
        {
            _dictionaryBase = new Dictionary<TKey, TValue>();
        }

        internal Dictionary<TKey, TValue> DictionaryBase
        {
            get
            {
                return _dictionaryBase;
            }
        }

        public void Add(TKey key, TValue val)
        {
            this[key] = val;
            _keysIsNew = true;
        }

        public bool Remove(TKey key)
        {
            lock (_syncRoot)
            {
                if (_dictionaryBase.Remove(key))
                {
                    _keysIsNew = true;
                    return true;
                }
            }
            return false;
        }

        public void Clear()
        {
            lock (_syncRoot)
            {
                _dictionaryBase.Clear();
            }
            _keysIsNew = true;
        }

        public bool ContainsKey(TKey key)
        {
            lock (_syncRoot)
            {
                return _dictionaryBase.ContainsKey(key);
            }
        }

        public Dictionary<TKey, TValue>.KeyCollection Keys
        {
            get
            {
                lock (_syncRoot)
                {
                    return _dictionaryBase.Keys;
                }
            }
        }

        public Dictionary<TKey, TValue>.ValueCollection Values
        {
            get
            {
                lock (_syncRoot)
                {
                    return _dictionaryBase.Values;
                }
            }
        }

        public TKey[] AllKeys
        {
            get
            {
                if (_keysIsNew)
                {
                    lock (_syncRoot)
                    {
                        if (_keysIsNew)
                        {
                            _allKeys = _dictionaryBase.Keys.ToArray();
                            _keysIsNew = false;
                        }
                    }
                }
                return _allKeys;
            }
        }


        public TValue this[TKey key]
        {
            get
            {
                TValue v = default(TValue);
                try
                {
                    _dictionaryBase.TryGetValue(key, out v);
                }
                catch (System.Exception ex)
                {
                    LogManager.WriteErrorWithDescription("SynchronizedDictionary_Get:", ex);
                    lock (_syncRoot)
                    {
                        _dictionaryBase.TryGetValue(key, out v);
                    }
                }
                return v;
            }
            set
            {
                lock (_syncRoot)
                {
                    _dictionaryBase[key] = value;
                }
            }
        }

        public int Count
        {
            get
            {
                lock (_syncRoot)
                {
                    return _dictionaryBase.Count;
                }
            }
        }

        public object SyncRoot
        {
            get
            {
                return _syncRoot;
            }
        }
    }