要同步对我的属性的访问,我使用ReaderWriterLockSlim类。我使用以下代码以线程安全的方式访问我的属性。
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方法使用IsReadLockHeld
属性和IsWriteLockHeld
ReaderWriterLockSlim
属性检查是否已获取锁定。这很好,并且提高了我的代码的性能。
到目前为止一直很好,但是当我重新阅读有关IsReadLockHeld
和IsWriteLockHeld
的文档时,我注意到了Microsoft的评论:
此属性旨在用于断言或其他调试 目的。不要用它来控制程序执行的流程。
我的问题是:为什么我不应该为此目的使用IsReadLockHeld/IsWriteLockHeld
?我的代码有什么问题吗?一切都按预期工作,比使用递归锁(LockRecursionPolicy.SupportsRecursion
)快得多。
澄清一下:这是一个很小的例子。我不想知道锁本身是否必要,或者是否可以以不同方式移除或实现。我只是想知道为什么我不应该使用IsReadLockHeld
/ IsWriteLockHeld
来控制文档所述的程序流程。
答案 0 :(得分:13)
经过一些进一步的研究后,我在German Support Forum of the Microsoft Developer Network上发布了同样的问题,并与非常有帮助的主持人 Marcel Roma 进行了讨论。他能够联系撰写此答案的ReaderWriterLockSlim
Joe Duffy 的程序员:
我担心我的答案会留下一些不足之处。
该物业运作正常,并记录在案。指导真的很公正 因为有条件的获取和释放锁定往往是错误的 在实践中容易出错,特别是在抛出异常的情况下 混合。
构建代码通常是个好主意 使用递归获取,或者你没有,(当然后者是 总是更容易推理);使用像IsReadLockHeld这样的属性 你把它放在中间的某个地方。
我是RWLS的主要设计师之一,我不得不承认它 太多的花里胡哨了。我不一定后悔补充 IsReadLockHeld - 因为它可以派上用场进行调试和断言 - 但是一旦我们添加它,Pandora的盒子就被打开了,我们RWLS立即开启了这种用途。
我并不感到惊讶,人们想要使用它,如图所示 StackOverflow线程,我确信有一些合法的场景 它比替代品更好地工作。我只是建议犯错误 不使用它的一面。
总结一下:您可以使用IsReadLockHeld
和IsWriteLockHeld
属性有条件地获取锁定,一切都会正常工作,但编程样式不好,一个人应该避免它。坚持递归或非递归锁定更好。要保持良好的编码样式,IsReadLockHeld
和IsWriteLockHeld
应仅用于调试目的。
我要再次感谢Marcel Roma和Joe Duffy的宝贵帮助。
答案 1 :(得分:-2)
文档建议你做对了。
考虑以下交错执行。
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方法的确切定义。