【问题标题】:ReaderWriterLockSlim vs Double Lock Check patternReaderWriterLockSlim vs 双锁检查模式
【发布时间】:2013-01-08 12:59:11
【问题描述】:

编辑:从我已经得到的答案中,我了解到我提出的第一个解决方案并不是真正的“不阻塞读取”,因为只有一个线程可以进入可升级锁而写锁不能在阅读发布之前采取...

所以我的问题是,如果不存在,如何以正确的方式使第一个解决方案成为“非阻塞读取”的创建?


我试图了解非阻塞多线程读取的两种解决方案。下面两种解决方案有什么区别(可能有些东西我还是不明白,但我在尝试):

/// <summary>
/// ReaderWriterLockSlim pattern
/// </summary>
public class ReadWriteLockCheck
{
    Dictionary<string, object> _dict = new Dictionary<string, object>();

    private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

    public void CreateByKey(string key)
    {
        _rwLock.EnterReadLock();
        try
        {
            if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists
            {
                _rwLock.EnterWriteLock(); //Lock
                try
                {
                    _dict.Add(key, new object());
                }
                finally
                {
                    _rwLock.ExitWriteLock();
                }
            }
        }
        finally
        {
            _rwLock.ExitReadLock();
        }
    }

    public bool GetByKey(string key)
    {
        _rwLock.EnterWriteLock();
        try
        {
            if (_dict.ContainsKey(key)) //Non blocking read
            {
                return true;
            }

            return false;
        }
        finally
        {
            _rwLock.ExitReadLock();
        }
    }
}

/// <summary>
/// Double check lock pattern
/// </summary>
public class MonitorLock
{
    Dictionary<string, object> _dict = new Dictionary<string, object>();

    private object _syncObj = new Object();

    public void CreateByKey(string key)
    {
        if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists
        {
            Monitor.Enter(_syncObj); //Lock
            try
            {
                if (!_dict.ContainsKey(key)) //Check if between first check and lock someone already added
                {
                    _dict.Add(key, new object());
                }
            }
            finally
            {
                Monitor.Exit(_syncObj);
            }
        }
    }

    public bool GetByKey(string key)
    {
        if (_dict.ContainsKey(key)) //Non blocking read
        {
            return true;
        }

        return false;
    }
}

在我看来,这两种解决方案都可以进行非阻塞读取,并且仅在写入时阻塞...如果是这样,ReaderWriterLockSlim 有什么好处?正如我在 google 中发现的,MonitorReaderWriterLockSlim 快得多。 当然,我知道我在阅读时可能会得到不正确的字典状态,但这对我来说没关系。
谢谢

【问题讨论】:

  • 为什么不选择一个已经发明的轮子呢? System.Collections.Concurrent.ConcurrentDictionary&lt;TKey, TValue&gt;? msdn.microsoft.com/en-us/library/dd287191.aspx
  • 使用 Monitor.Enter / Monitor.Exit 没有任何好处 - 只需使用 lock;除了更简单之外,它还可以更好地处理一些边缘情况(如果可以,它会使用Enter的不同重载)
  • @spender 我看到了,但是这个类从 .NET 4 开始可用,我们使用 3.5 :(
  • @MarcGravell 这是一个非常简单的例子,我真的不能使用 lock{...} 因为锁定/解锁是在另一个管理器对象中完成的。

标签: c# .net multithreading locking readerwriterlockslim


【解决方案1】:

From MSDN:

任何时候只有一个线程可以进入升级模式

基本上,您并没有比仅使用全锁更好 - 除了lock 实际上会更快。

奇怪的是,这里的一个好方法是Hashtable;特别是因为值是object,并且键是引用类型(没有额外的装箱)。 Hashtable 的不寻常之处在于 reads 是完全线程安全的;你只需要防范多个writers

例如:

readonly Hashtable lookup = new Hashtable();

...

object val = lookup[key]; // no need to synchronize when reading

...

lock(lookup)
{
    lookup[key] = newVal; // synchronize when writing
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多