C# 微软';s对ReaderWriterLockSlim.isReadLockHold/isWriteLockHold的评论及其后果
要同步对我的属性的访问,我使用类。我使用以下代码以线程安全的方式访问我的属性C# 微软';s对ReaderWriterLockSlim.isReadLockHold/isWriteLockHold的评论及其后果,c#,readerwriterlockslim,C#,Readerwriterlockslim,要同步对我的属性的访问,我使用类。我使用以下代码以线程安全的方式访问我的属性 public class SomeClass { public readonly ReaderWriterLockSlim SyncObj = new ReaderWriterLockSlim(); public string AProperty { get { if (SyncObj.IsReadLockHeld)
public class SomeClass
{
public readonly ReaderWriterLockSlim SyncObj = new ReaderWriterLockSlim();
public string AProperty
{
get
{
if (SyncObj.IsReadLockHeld)
return ComplexGetterMethod();
SyncObj.EnterReadLock();
try
{
return ComplexGetterMethod();
}
finally
{
SyncObj.ExitReadLock();
}
}
set
{
if (SyncObj.IsWriteLockHeld)
ComplexSetterMethod(value);
else
{
SyncObj.EnterWriteLock();
ComplexSetterMethod(value);
SyncObj.ExitWriteLock();
}
}
}
// more properties here ...
private string ComplexGetterMethod()
{
// This method is not thread-safe and reads
// multiple values, calculates stuff, ect.
}
private void ComplexSetterMethod(string newValue)
{
// This method is not thread-safe and reads
// and writes multiple values.
}
}
// =====================================
public static SomeClass AClass = new SomeClass();
public void SomeMultiThreadFunction()
{
...
// access with locking from within the setter
AClass.AProperty = "new value";
...
// locking from outside of the class to increase performance
AClass.SyncObj.EnterWriteLock();
AClass.AProperty = "new value 2";
AClass.AnotherProperty = "...";
...
AClass.SyncObj.ExitWriteLock();
...
}
为了避免在每次获取或设置多个属性时进行不必要的锁定,我发布了ReaderWriterLockSlim
-对象,并在每次获取或设置一组属性时从类外部锁定它。为此,我的getter和setter方法使用readerwriterlocksim
的isreadlockhold
属性和iswritelockhold
属性检查是否已获取锁。这很好,提高了代码的性能
到目前为止还不错,但当我重新阅读有关isreadlockhold
和iswritelockhold
的文档时,我注意到微软的评论:
此属性用于断言或其他调试
目的。不要用它来控制程序执行的流程
Thread1.AcqrireReadLock();
Thread1.ComplexGetterMethod();
Thread2.ReadIsReaderLockHeldProperty();
Thread1.ReleaseReadLock();
Thread2.ComplexGetterMethod(); // performing read without lock.
我的问题是:是否有理由不使用isreadlockhold/iswritelockhold
?我的代码有什么问题吗?一切都按预期运行,比使用递归锁快得多(LockRecursionPolicy.SupportsRecursion
)
为了澄清这一点:这是一个最小的例子。我不想知道锁本身是否有必要,或者可以用不同的方式移除或实现。我只是想知道为什么我不应该使用
isreadlockhold
/iswritelockhold
来控制文档中所述的程序流 文档为您提供了正确的建议
请考虑以下交错执行
Thread1.AcqrireReadLock();
Thread1.ComplexGetterMethod();
Thread2.ReadIsReaderLockHeldProperty();
Thread1.ReleaseReadLock();
Thread2.ComplexGetterMethod(); // performing read without lock.
我看到你的代码的另一个错误是
SyncObj.EnterReadLock();
try
{
return ComplexGetterMethod();
}
finally
{
SyncObj.ExitReadLock();
}
这不是正确的做事方式。这是一项权利:
try
{
SyncObj.EnterReadLock();
return ComplexGetterMethod();
}
finally
{
if (SyncObj.IsReadLockHeld)
SyncObj.ExitReadLock();
}
这将是你的getter方法的确切定义。经过进一步的研究,我在网上发布了同样的问题,并与非常有用的主持人Marcel Roma进行了讨论。他能够联系到写下以下答案的
ReaderWriterLockSlim
Joe Duffy的程序员:
我恐怕我的回答会留下一些不尽如人意的地方
该物业运作良好,符合文件规定。指导真的很公正
因为有条件地获取和释放锁往往是有缺陷的
而且在实践中容易出错,特别是在将异常抛出到
混合
通常,构造代码的结构是一个好主意,以便
使用递归获取,或者不使用(当然后者是
总是更容易推理);使用像isReadLockHold这样的属性
把你放在中间的某个地方。< /P>
我是RWLS的主要设计师之一,我不得不承认它是
太多的钟声和口哨声了。我不一定会后悔添加
IsReadLockHold——因为它可以方便地用于调试和断言
--然而,我们一加上它,潘多拉的盒子就被打开了,我们RWLS立刻被打开了,接受这种使用
我并不感到惊讶,人们希望使用它,如图所示
StackOverflow线程,我确信有一些合法的场景
它比其他替代方案更有效。我只是建议你犯错误
不使用它的一面
总而言之:您可以使用isreadlockhold
和iswritelockhold
属性有条件地获取锁,一切都可以正常工作,但这是一种糟糕的编程风格,应该避免。最好坚持使用递归锁或非递归锁。为了保持良好的编码风格,isreadlockhold
和iswritelockhold
应仅用于调试目的
我想再次感谢马塞尔·罗马和乔·达菲的宝贵帮助 ReaderWriteLockSlim不保护任何东西,.NET已经承诺对象引用更新是原子的。它唯一轻微的副作用是setter更新将在其他线程中可见。只使用MemoryBarrier()要便宜得多。没有线程安全保证,完全删除SyncObj当然更好,因为它只会给人一种错误的安全感。@EricLippert:IsRead/WriteLockHold的文档建议在当前线程持有锁时返回
true
。如果IsRead/writelockhold
返回true,那么在没有显式调用exitrade/WriteLock
的情况下,该线程上的锁状态如何发生更改?@Iridium:I撤回我的评论;我现在真的不知道为什么文档中会有这样的警告。也就是说:最佳实践是按照文档中所说的去做。您会问“这个代码有什么问题吗?”。是的,有。试图猜测代码中有我们看不到的错误是非常徒劳无益的。SyncObj
应该是只读的,这样就永远不会被替换掉。这一点更为正确,因为您已将其公开。这种执行不会以这种方式发生,因为只有当当前线程持有锁时,isreadlockhold
才会返回true
。