C# ReaderWriterLockSlim与双锁检查模式

C# ReaderWriterLockSlim与双锁检查模式,c#,.net,multithreading,locking,readerwriterlockslim,C#,.net,Multithreading,Locking,Readerwriterlockslim,编辑:从我已经得到的答案中,我了解到我提出的第一个解决方案并不是真正的“不阻止读取”,因为只有一个线程可以进入可升级锁,并且在读取被释放之前不能使用写锁 因此,我的问题是,如果不存在,如何以正确的方式使第一个解决方案成为“非阻塞读取”,并进行创建 我试图了解非阻塞多线程读取的两种解决方案。以下两种解决方案的区别是什么(也许我仍然不理解某些事情,但我正在尝试): // ///ReaderWriterLockSlim模式 /// 公共类ReadWriteLockCheck { 字典_dict=新

编辑:从我已经得到的答案中,我了解到我提出的第一个解决方案并不是真正的“不阻止读取”,因为只有一个线程可以进入可升级锁,并且在读取被释放之前不能使用写锁

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


我试图了解非阻塞多线程读取的两种解决方案。以下两种解决方案的区别是什么(也许我仍然不理解某些事情,但我正在尝试):

//
///ReaderWriterLockSlim模式
/// 
公共类ReadWriteLockCheck
{
字典_dict=新字典();
私有ReaderWriterLockSlim _rBlock=新的ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
public void CreateByKey(字符串键)
{
_rwLock.EnterReadLock();
尝试
{
if(!\u dict.ContainsKey(key))//非阻塞读取-检查是否存在
{
_rwLock.EnterWriteLock();//锁
尝试
{
_dict.Add(键,新对象());
}
最后
{
_rBlock.ExitWriteLock();
}
}
}
最后
{
_rwLock.exitradlock();
}
}
公共bool GetByKey(字符串键)
{
_rBlock.EnterWriteLock();
尝试
{
if(_dict.ContainsKey(key))//非阻塞读取
{
返回true;
}
返回false;
}
最后
{
_rwLock.exitradlock();
}
}
}
/// 
///双重检查锁定模式
/// 
公共类监视器锁
{
字典_dict=新字典();
私有对象_syncObj=新对象();
public void CreateByKey(字符串键)
{
if(!\u dict.ContainsKey(key))//非阻塞读取-检查是否存在
{
Monitor.Enter(_syncObj);//Lock
尝试
{
if(!\u dict.ContainsKey(key))//检查在首次检查和锁定之间是否已经添加了某人
{
_dict.Add(键,新对象());
}
}
最后
{
监视器。退出(_syncObj);
}
}
}
公共bool GetByKey(字符串键)
{
if(_dict.ContainsKey(key))//非阻塞读取
{
返回true;
}
返回false;
}
}
在我看来,这两种解决方案都可以进行非阻塞读取,并且在写入时只进行阻塞…如果是这样,那么
readerwriterlocksim
有什么好处?正如我在谷歌中发现的那样,
Monitor
ReaderWriterLockSlim
快得多。 当然,我知道在阅读时可能会出现字典的错误状态,但这对我来说没关系。
谢谢

在任何给定时间,只有一个线程可以进入可升级模式

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

奇怪的是,这里有一个很好的方法是
哈希表
;特别是因为值是
对象
,并且键是引用类型(没有额外的装箱)
Hashtable
是不寻常的,因为读取是完全线程安全的;您只需防范多个编写器

例如:

readonly Hashtable lookup = new Hashtable();

...

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

...

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

为什么不选择一个已经发明的轮子呢<代码>系统.集合.并发.并发字典?使用
监视器没有任何好处。输入
/
监视器。退出
,只需使用
锁定
;除了更简单之外,它还可以更好地处理一些边缘情况(它可以使用不同的重载
Enter
)@spender我看到了它,但该类从.NET 4开始就可用,我们使用3.5:(@marcGravel这是一个非常简化的示例,我真的不能使用lock{…}因为锁定/解锁是在另一个管理器对象中完成的。好的,我明白了…如果我将行_rBlock.EnterUpgradeableReadLock()更改为_rBlock.EnterReadLock());这有意义吗?另一点…你说Hashtable可以在线程安全模式下读取…这到底意味着什么?这是否意味着当我使用字典并试图读取值时,除了“不一致的对象状态”之外,我可能会遇到一些意想不到的问题?@AlexDn是第一个;如果您使用
EnterReadLock
,您必须在尝试获取写锁之前退出读锁;两者是完全分开的。re是后者:确实
字典
不能保证这一点,因此使用字典时,您必须确保没有编写者,甚至没有编写者来执行读操作。是的:没有这一点,您就可以疯狂。使用
哈希表
你不需要它;读卡器只是读取-根本不需要同步。只有写卡器需要同步。这大大简化了事情。那么,在使用无锁字典时,我会遇到一些异常吗?或者在我的情况下,它会产生什么样的问题?@AlexDn是的,读与写并行在字典中可能导致异常。MSDN确认:
Dictionary
vs
Hashtable
readonly Hashtable lookup = new Hashtable();

...

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

...

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