带有ReaderWriterLockSlim的C#字典

时间:2009-08-25 19:10:04

标签: c# asp.net caching dictionary thread-safety

我对多线程非常陌生,出于某种原因,这门课给我带来了比它应该更多的麻烦。

我在ASP.net缓存中设置一个字典 - 经常查询单个对象,偶尔枚举,并且很少写入。我会注意到字典数据几乎从未改变过,我计划让它每天过期,并在离开缓存时从数据库重建回调。

我相信只要字典没有被写入,按键的枚举和访问就是安全的。我在想一个基于ReaderWriterLockSlim的包装类是要走的路,但我在几点上模糊了。

如果我使用Lock,我相信我可以锁定令牌或我正在保护的实际对象。我没有看到如何使用ReaderWriter Lock做类似的事情。我是否认为我的包装器的多个实例无法正确锁定,因为ReaderWriterLocks不在彼此的范围内?

编写这样的包装器的最佳做法是什么?将其构建为静态几乎看起来是多余的,因为主要对象由缓存维护。单身人士似乎不赞成,我担心上面提到的个别实例的范围界定问题。

我见过几个类似包装的实现,但我无法回答这些问题。我只是想确保我已经牢牢掌握了我正在做的事情,而不是切割和切割。粘贴我的方式。非常感谢你的帮助!


**编辑:希望这是对我想要找到的内容的更清晰的总结 - **

1。我是否认为锁不会影响基础数据并且其范围与任何其他变量一样?

举一个例子,假设我有以下内容 -

MyWrapperClass 
{
    ReaderWriterLockSlim lck = new ReaderWriterLockSlim();
    Do stuff with this lock on the underlying cached dictionary object...
}

MyWrapperClass wrapA = new MyWrapperClass();
MyWrapperClass wrapB = new MyWrapperClass();

我认为wrapA锁和wrapB锁不会相互影响,而且如果是wrapA& wrapB两次尝试操作都会不安全吗?

2。如果是这种情况,“共享”锁定数据的最佳做法是什么?

这是一个Asp.net应用程序 - 会有多个页面需要访问数据,这就是为什么我这样做的原因。确保各种包装使用相同锁的最佳做法是什么?我的包装器应该是所有线程都使用的静态或单例,如果不是更优雅的选择吗?

3 个答案:

答案 0 :(得分:6)

缓存中有多个字典对象,您希望每个字体对象独立锁定。 “最好”的方法就是使用一个简单的类来为你做这件事。

public class ReadWriteDictionary<K,V>
{
    private readonly Dictionary<K,V> dict = new Dictionary<K,V>();
    private readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

    public V Get(K key)
    {
        return ReadLock(() => dict[key]);
    }

    public void Set(K key, V value)
    {
        WriteLock(() => dict.Add(key, value));
    }

    public IEnumerable<KeyValuePair<K, V>> GetPairs()
    {
        return ReadLock(() => dict.ToList());
    }

    private V2 ReadLock<V2>(Func<V2> func)
    {
        rwLock.EnterReadLock();
        try
        {
            return func();
        }
        finally
        {
            rwLock.ExitReadLock();
        }
    }

    private void WriteLock(Action action)
    {
        rwLock.EnterWriteLock();
        try
        {
            action();
        }
        finally
        {
            rwLock.ExitWriteLock();
        }
    }
}

Cache["somekey"] = new ReadWriteDictionary<string,int>();

ReaderWriterLockSlim on MSDN的帮助页面上还有一个更完整的示例。将它变为通用并不难。

编辑回答您的新问题 -

1。)你是正确的wrapA,wrapB不会互动。他们都有自己的ReaderWriterLockSlim实例。

2.。)如果你需要在所有包装类中使用共享锁,那么它必须是静态的。

答案 1 :(得分:1)

ConcurrentDictionary做你想要的一切,然后做一些。 System.Concurrent.Collections的一部分

答案 2 :(得分:-1)

锁定的标准方法是:object lck = new object(); ... lock(lck) { ... }在此实例中,对象lck表示锁定。

ReadWriterLockSlim没有太大的不同,它只是在这种情况下实际的ReadWriterLockSlim类代表实际的锁,所以无论你在哪里使用lck,你现在都使用你的ReadWriterLockSlim。

ReadWriterLockSlim lck = new ReadWriterLockSlim();

...

lck.EnterReadLock();
try
{
    ...
}
finally
{
    lck.ExitReadLock();
}