none
如何在 Dictionary<> 上面实现,写同步锁,读共享锁。 RRS feed

  • 问题

  • 一般在多线程操作字典集合的时候,会不停的遍历,但是也会在某几个线程中对字典进行修改,如何做到在读字典的时候都是共享的,而在写的时候进行锁定,直到写完之后,才可以继续共享锁。


    Sherrys
    2009年7月16日 4:30

答案

  • 你好 这是我自己写的一个实现  使用了  3.5 的lock slim


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Threading;
    using System.Security.Permissions;
    
    
    
    namespace System.Collections.Generic.Sync
    {
    
      public   class SyncDictionary<TKey, TValue> : Dictionary<TKey, TValue>
        {
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    
            public new void Add(TKey key, TValue value)
            {
                _lock.EnterWriteLock();
                base.Add(key, value);
                _lock.ExitWriteLock();
    
            }
    
            public new void Clear()
            {
                _lock.EnterWriteLock();
                base.Clear();
                _lock.ExitWriteLock();
    
            }
            public new bool ContainsKey(TKey key)
            {
                _lock.EnterReadLock();
                var rv = base.ContainsKey(key);
                _lock.ExitReadLock();
                return rv;
            }
    
    
    
            public new bool ContainsValue(TValue value)
            {
                _lock.EnterReadLock();
                var rv = base.ContainsValue(value);
                _lock.ExitReadLock();
                return rv;
            }
    
    
            public new Dictionary<TKey, TValue>.Enumerator GetEnumerator()
            {
                _lock.EnterReadLock();
                var rv = new Dictionary<TKey, TValue>(this).GetEnumerator();
                _lock.ExitReadLock();
                return rv;
            }
            public new bool Remove(TKey key)
            {
                _lock.EnterWriteLock();
                var rv = base.Remove(key);
                _lock.ExitWriteLock();
                return rv;
    
            }
            public new bool TryGetValue(TKey key, out TValue value)
            {
                _lock.EnterReadLock();
                var rv = base.TryGetValue(key, out value);
                _lock.ExitReadLock();
                return rv;
    
            }
    
    
            public new int Count
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = base.Count;
                    _lock.ExitReadLock();
                    return rv;
                }
    
            }
    
    
            public new TValue this[TKey key]
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = base[key];
                    _lock.ExitReadLock();
                    return rv;
                }
                set
                {
                    _lock.EnterWriteLock();
                    base[key] = value;
                    _lock.ExitWriteLock();
           
                }
            }
    
    
            public  new Generic.Dictionary <TKey, TValue>.KeyCollection Keys
            {
                get
                {
    
                    _lock.EnterReadLock();
                    var rv = base.Keys;
                    _lock.ExitReadLock();
                    return rv;
                }
    
            }
    
            public new Generic.Dictionary<TKey, TValue>.ValueCollection Values
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = base.Values;
                    _lock.ExitReadLock();
                    return rv;
                }
    
            }
     
    
     
    
       
    
    
    
        }
    }
    

    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    • 已标记为答案 Sherrys 2009年7月16日 5:35
    2009年7月16日 5:02
    版主
  • 如果你的工程中 这个字典不能修改了   可以用下面这个adepter 把原来的字典封装起来   以后访问这个引用就可以实现读写锁



    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Threading;
    using System.Security.Permissions;
    
    
    
    namespace System.Collections.Generic.Sync
    {
    
        public class SyncDictionaryAdapter<TKey, TValue> : IDictionary<TKey, TValue>
        {
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
            Dictionary<TKey, TValue> BaseDictionary { get; set; }
            private   ICollection<KeyValuePair<TKey, TValue>> BaseCollection
            {
                get
                { return (ICollection<KeyValuePair<TKey, TValue>>)BaseDictionary; }
               
            }
            public SyncDictionaryAdapter(Dictionary<TKey, TValue> Dictionary)
            {
                BaseDictionary = Dictionary;
            }
    
    
    
    
    
    
    
    
            #region IDictionary<TKey,TValue> Members
    
            public void Add(TKey key, TValue value)
            {
                _lock.EnterWriteLock();
                BaseDictionary.Add(key, value);
                _lock.ExitWriteLock();
            }
    
            public bool ContainsKey(TKey key)
            {
                 
                _lock.EnterReadLock();
                var rv = BaseDictionary .ContainsKey(key);
                _lock.ExitReadLock();
                return rv;
            }
    
            public ICollection<TKey> Keys
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary.Keys;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public bool Remove(TKey key)
            {
                _lock.EnterWriteLock();
                var rv = BaseDictionary.Remove(key);
                _lock.ExitWriteLock();
                return rv;
            }
    
            public bool TryGetValue(TKey key, out TValue value)
            {
                _lock.EnterReadLock();
                var rv = BaseDictionary.TryGetValue(key, out value);
                _lock.ExitReadLock();
                return rv;
            }
    
            public ICollection<TValue> Values
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary.Values;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public TValue this[TKey key]
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary[key];
                    _lock.ExitReadLock();
                    return rv;
                }
                set
                {
                    _lock.EnterWriteLock();
                    BaseDictionary[key] = value;
                    _lock.ExitWriteLock();
    
                }
            }
    
            #endregion
    
            #region ICollection<KeyValuePair<TKey,TValue>> Members
    
            public void Add(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterWriteLock();
                BaseCollection.Add(item);
                _lock.ExitWriteLock ();
              
            }
    
            public void Clear()
            {
                _lock.EnterWriteLock();
                BaseCollection.Clear ();
                _lock.ExitWriteLock();
            }
    
            public bool Contains(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterReadLock ();
                var rv = BaseCollection.Contains(item);
                _lock.ExitReadLock ();
                return rv;
    
            }
    
            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
            {
                _lock.EnterReadLock();
                BaseCollection.CopyTo(array, arrayIndex);
                _lock.ExitReadLock();
            }
    
            public int Count
            {
                get {
                    _lock.EnterReadLock();
                    var rv = BaseCollection.Count;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public bool IsReadOnly
            {
                get
                {
    
                    return BaseCollection.IsReadOnly;
    
                }
            }
    
            public bool Remove(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterWriteLock ();
                var rv = BaseCollection.Remove(item);
                _lock.ExitWriteLock();
                return rv;
            }
    
            #endregion
    
            #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
            {
                return BaseDictionary.GetEnumerator();
            }
    
            #endregion
    
            #region IEnumerable Members
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return BaseDictionary.GetEnumerator();
            }
    
            #endregion
        }
    }

    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年7月16日 5:03
    版主
  • 1 不会有问题


    2 第二个不是真正的dic的实例   而是一个套子  也就是代理   你在建立这个代理后  把你从别的地方得到的字典放进去  

    这时候访问这个代理类的所有请求都会具有  写同步锁读共享, 而不必继承或者修改原来的dic代码

    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    • 已标记为答案 Sherrys 2009年7月16日 5:46
    2009年7月16日 5:43
    版主

全部回复

  • private object lockObj = new object();
    private Dictionary<string, object> fCacheItem = new Dictionary<string, object>();
    
    public Dictionary<string, object> CacheItem
    {
        get { return fCacheItem; }
        set 
        {
            lock (lockObj)
            {
                fCacheItem = value;
            }
        }
    }


    知识改变命运,奋斗成就人生!
    2009年7月16日 4:42
    版主
  • 如果把上面的方法写成一个类 A。

    如果每次需要一个字典对象,new A() 然后通过 Dictionary<string,object> dic = a.CacheItem();

    这样能确保在 dic.Add Remove 等更新 写入操作的时候同步吗?


    而且现在的情况是,在写、更新的过程中,也是不允许 get 的,上述的实现方式只是保证了写入的同步,但是却不能保证在写的时候不允许进行读取的;而在非写入更新的状态下,是可以共享读取 dic 里面的数据的。


    Sherrys
    2009年7月16日 4:52
  • 不能,你可能需要在 A 类中自己写 Add, Remove 方法来对字典进行操作,并在这些方法里面加锁
    知识改变命运,奋斗成就人生!
    2009年7月16日 5:00
    版主
  • 你好 这是我自己写的一个实现  使用了  3.5 的lock slim


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Threading;
    using System.Security.Permissions;
    
    
    
    namespace System.Collections.Generic.Sync
    {
    
      public   class SyncDictionary<TKey, TValue> : Dictionary<TKey, TValue>
        {
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    
            public new void Add(TKey key, TValue value)
            {
                _lock.EnterWriteLock();
                base.Add(key, value);
                _lock.ExitWriteLock();
    
            }
    
            public new void Clear()
            {
                _lock.EnterWriteLock();
                base.Clear();
                _lock.ExitWriteLock();
    
            }
            public new bool ContainsKey(TKey key)
            {
                _lock.EnterReadLock();
                var rv = base.ContainsKey(key);
                _lock.ExitReadLock();
                return rv;
            }
    
    
    
            public new bool ContainsValue(TValue value)
            {
                _lock.EnterReadLock();
                var rv = base.ContainsValue(value);
                _lock.ExitReadLock();
                return rv;
            }
    
    
            public new Dictionary<TKey, TValue>.Enumerator GetEnumerator()
            {
                _lock.EnterReadLock();
                var rv = new Dictionary<TKey, TValue>(this).GetEnumerator();
                _lock.ExitReadLock();
                return rv;
            }
            public new bool Remove(TKey key)
            {
                _lock.EnterWriteLock();
                var rv = base.Remove(key);
                _lock.ExitWriteLock();
                return rv;
    
            }
            public new bool TryGetValue(TKey key, out TValue value)
            {
                _lock.EnterReadLock();
                var rv = base.TryGetValue(key, out value);
                _lock.ExitReadLock();
                return rv;
    
            }
    
    
            public new int Count
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = base.Count;
                    _lock.ExitReadLock();
                    return rv;
                }
    
            }
    
    
            public new TValue this[TKey key]
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = base[key];
                    _lock.ExitReadLock();
                    return rv;
                }
                set
                {
                    _lock.EnterWriteLock();
                    base[key] = value;
                    _lock.ExitWriteLock();
           
                }
            }
    
    
            public  new Generic.Dictionary <TKey, TValue>.KeyCollection Keys
            {
                get
                {
    
                    _lock.EnterReadLock();
                    var rv = base.Keys;
                    _lock.ExitReadLock();
                    return rv;
                }
    
            }
    
            public new Generic.Dictionary<TKey, TValue>.ValueCollection Values
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = base.Values;
                    _lock.ExitReadLock();
                    return rv;
                }
    
            }
     
    
     
    
       
    
    
    
        }
    }
    

    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    • 已标记为答案 Sherrys 2009年7月16日 5:35
    2009年7月16日 5:02
    版主
  • 如果你的工程中 这个字典不能修改了   可以用下面这个adepter 把原来的字典封装起来   以后访问这个引用就可以实现读写锁



    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Threading;
    using System.Security.Permissions;
    
    
    
    namespace System.Collections.Generic.Sync
    {
    
        public class SyncDictionaryAdapter<TKey, TValue> : IDictionary<TKey, TValue>
        {
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
            Dictionary<TKey, TValue> BaseDictionary { get; set; }
            private   ICollection<KeyValuePair<TKey, TValue>> BaseCollection
            {
                get
                { return (ICollection<KeyValuePair<TKey, TValue>>)BaseDictionary; }
               
            }
            public SyncDictionaryAdapter(Dictionary<TKey, TValue> Dictionary)
            {
                BaseDictionary = Dictionary;
            }
    
    
    
    
    
    
    
    
            #region IDictionary<TKey,TValue> Members
    
            public void Add(TKey key, TValue value)
            {
                _lock.EnterWriteLock();
                BaseDictionary.Add(key, value);
                _lock.ExitWriteLock();
            }
    
            public bool ContainsKey(TKey key)
            {
                 
                _lock.EnterReadLock();
                var rv = BaseDictionary .ContainsKey(key);
                _lock.ExitReadLock();
                return rv;
            }
    
            public ICollection<TKey> Keys
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary.Keys;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public bool Remove(TKey key)
            {
                _lock.EnterWriteLock();
                var rv = BaseDictionary.Remove(key);
                _lock.ExitWriteLock();
                return rv;
            }
    
            public bool TryGetValue(TKey key, out TValue value)
            {
                _lock.EnterReadLock();
                var rv = BaseDictionary.TryGetValue(key, out value);
                _lock.ExitReadLock();
                return rv;
            }
    
            public ICollection<TValue> Values
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary.Values;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public TValue this[TKey key]
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary[key];
                    _lock.ExitReadLock();
                    return rv;
                }
                set
                {
                    _lock.EnterWriteLock();
                    BaseDictionary[key] = value;
                    _lock.ExitWriteLock();
    
                }
            }
    
            #endregion
    
            #region ICollection<KeyValuePair<TKey,TValue>> Members
    
            public void Add(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterWriteLock();
                BaseCollection.Add(item);
                _lock.ExitWriteLock ();
              
            }
    
            public void Clear()
            {
                _lock.EnterWriteLock();
                BaseCollection.Clear ();
                _lock.ExitWriteLock();
            }
    
            public bool Contains(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterReadLock ();
                var rv = BaseCollection.Contains(item);
                _lock.ExitReadLock ();
                return rv;
    
            }
    
            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
            {
                _lock.EnterReadLock();
                BaseCollection.CopyTo(array, arrayIndex);
                _lock.ExitReadLock();
            }
    
            public int Count
            {
                get {
                    _lock.EnterReadLock();
                    var rv = BaseCollection.Count;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public bool IsReadOnly
            {
                get
                {
    
                    return BaseCollection.IsReadOnly;
    
                }
            }
    
            public bool Remove(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterWriteLock ();
                var rv = BaseCollection.Remove(item);
                _lock.ExitWriteLock();
                return rv;
            }
    
            #endregion
    
            #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
            {
                return BaseDictionary.GetEnumerator();
            }
    
            #endregion
    
            #region IEnumerable Members
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return BaseDictionary.GetEnumerator();
            }
    
            #endregion
        }
    }

    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年7月16日 5:03
    版主
  • 如果仅仅靠一个 A 类来封装的话,可能无法实现,是否有一个比较好的继承方法来实现 Dic 的这种要求呢?

    还有现在主要的问题就是,怎么在 Dic 更新操作的时候,Get 也是需要锁住的,直到更新锁释放,记得有过这种更新锁读取锁相关的类,但是忘记了,望指点。


    Sherrys
    2009年7月16日 5:06
  • 我给你的就是更新锁全部  读取互相不锁的代码     看代码  readwritelockslim 就是你要的


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年7月16日 5:10
    版主
  • 我给你的就是更新锁全部  读取互相不锁的代码     看代码  readwritelockslim 就是你要的


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。

    你给的正是我需要的,就是这个 Slim 。

    不过请问下,如果使用你第一个代码片段,如果所有的 Dic 都使用 new SyncDictionary() 是否会有问题。?

    关于你第二个进行封装,这样跟第一种的区别在哪里?因为还是可以对 Dic 进行修改,所以不是很理解。
    Sherrys
    2009年7月16日 5:35
  • 1 不会有问题


    2 第二个不是真正的dic的实例   而是一个套子  也就是代理   你在建立这个代理后  把你从别的地方得到的字典放进去  

    这时候访问这个代理类的所有请求都会具有  写同步锁读共享, 而不必继承或者修改原来的dic代码

    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    • 已标记为答案 Sherrys 2009年7月16日 5:46
    2009年7月16日 5:43
    版主
  • 能明白了,多谢 韦恩卑鄙。


    Sherrys
    2009年7月16日 5:47
  • 我给你的就是更新锁全部  读取互相不锁的代码     看代码  readwritelockslim 就是你要的


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。

    你给的正是我需要的,就是这个 Slim 。

    不过请问下,如果使用你第一个代码片段,如果所有的 Dic 都使用 new SyncDictionary() 是否会有问题。?

    关于你第二个进行封装,这样跟第一种的区别在哪里?因为还是可以对 Dic 进行修改,所以不是很理解。
    Sherrys

    请问,基于第二种 adapter 的写法,为何要使用接口 ICollection 来做引用呢,这样做对于使用 Dic 来说有什么好处?那样本来 Dic 的一些泛型方法,比如 ContainsKey 怎么才能使用?

    Sherrys
    2009年7月16日 15:04
  • ICollection  没有特别意义 :P 
    原来的泛型方法一直可以用啊


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年7月17日 4:57
    版主
  • private   ICollection<KeyValuePair<TKey, TValue>> BaseCollection
            {
                get
                { return (ICollection<KeyValuePair<TKey, TValue>>)BaseDictionary; }
              
            }

    因为你第二段代码通过使用 ICollection  来获取 BaseCollection 的对象引用。所以 BaseCollection 的方法就没有泛型的方法了。
    Sherrys
    2009年7月17日 6:07
  • 你可以自己(强行)转换哦


    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年7月21日 5:46
    版主
  • 明白了。


    Sherrys
    2009年7月21日 5:47