读书人

请问自定义Dictionary类怎么在类内实现

发布时间: 2012-02-05 12:07:15 作者: rapoo

请教自定义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;            }        }    } 


[解决办法]
如果采用产生副本的方法,对于客户代码来说,就不能象访问内置的Dictionary一样来访问自定义的Dictionary了


什么意思?
[解决办法]
将Dictionary包成HashTable试试?

C# code
Hashtable hash = Hashtable.Synchronized(new Hashtable((IDictionary)mDic));
[解决办法]

发生冲突的部分无非是在往Dictionary写值的时候,所以在离写Dictionary最近的地方加一个锁
syncRoot是自定义SafteDictionary内的互斥对象,哪个线程拿到它才可以对内部的Dictionary进行操作。
比如new Dictionary().Add加一个syncRoot的锁,变成
public void Add(TKey key, TValue value)
{
lock (syncRoot)
{
d.Add(key, value);
}
}
同一个时间点只能有一个线程能够访问d.Add(key, value);
示例下载:
http://files.cnblogs.com/kiddo/MultiThread.rar

以上信息来自:http://www.cnblogs.com/kiddo/archive/2008/09/25/1299089.html
LZ感兴趣可以看看
[解决办法]
我已上传到资源里面去下吧
http://download.csdn.net/source/1108764
[解决办法]
所谓的线程安全是站在某个具体环境下说的。而具体环境是由客户代码来构建的,因此安全一般由客户代码来负责......
对一个对象而言, 希望把它做成绝对安全的, 往往要么是花的设计成本太大,要么是性能仆街。
[解决办法]
探讨
谢谢两位大牛
如果采用产生副本的方法,对于客户代码来说,就不能象访问内置的Dictionary一样来访问自定义的Dictionary了
如果是那样的话,我感觉还是使用内置的Dictionary,让客户代码来保证线程安全。
难道没有更好的办法了?

[解决办法]
不推荐在多线程环境下使用共享的Dictionary进行写操作

可以使用一种相对代价较小的ReaderWriterLock来实现,
这种锁不会阻塞多个并行的读操作,
只会在有写操作进行时候才阻塞所有线程。

读书人网 >C#

热点推荐