我遇到过 ReaderWriterLockSlim 似乎在一系列法律行动后被破坏的场景。
流程是:
- 线程 1 获取 writer lock1
- 线程 2 尝试获取读者锁 1 - block
- 线程 2 被中断,并调用 lock1.ExitReadLock线程 2 没有获得锁。看来应该抛出异常了。
- 线程 1 退出 lock1 的写锁
- 任何试图获取 lock1.EnterReadLock 的线程都将永远阻塞
在上面的第 3 阶段之后,调试器显示 lock1.CurrentReadCount 已损坏 - 似乎已溢出到 0x7FFFFFF。
我想知道是否有人遇到过这种情况,或者我可能遗漏了什么。
重现它的代码:
[TestMethod]
public void ReproTest()
{
var rwlock = new ReaderWriterLockSlim();
rwlock.EnterWriteLock();
bool taken = false;
var reader = new Thread(() =>
{
try
{
rwlock.EnterReadLock();
s_logger.Info("Enter");
}
catch (ThreadInterruptedException)
{
rwlock.ExitReadLock();
}
});
reader.Name = "Reader";
reader.Start();
Thread.Sleep(1000);
reader.Interrupt();
Thread.Sleep(1000);
rwlock.ExitWriteLock();
while (!taken)
{
taken = rwlock.TryEnterReadLock(1000);
}
Thread.Sleep(1000);
}
这看起来像是框架中的一个错误(在 v3.5 和 v4.0 上测试过)。 ExitReadLock()
应该抛出一个 SynchronizationLockException
,但在这种情况下不会。事实上,您可以通过以下更简单地触发一个非常相似的问题:
rwlock.EnterReadLock();
rwlock.ExitReadLock();
// This should throw a SynchronizationLockException but doesn't
rwlock.ExitReadLock();
// At this point, rwlock.CurrentReaderCount = 0x0fffffff
(事实上,如果在之前进入锁的任何线程上调用时没有匹配的 EnterReadLock()
调用它,ExitReadLock()
将损坏锁。)
仅当使用无参数构造函数或使用 LockRecursionPolicy.NoRecursion
创建 ReaderWriterLockSlim
时才会出现此问题。如果使用 LockRecursionPolicy.SupportsRecursion
创建,它不会被不匹配的 ExitReadLock()
破坏。
如果您希望读取器线程在等待进入锁时被中断,我建议将读取器线程方法更改为:
var reader = new Thread(() =>
{
var entered = false;
try
{
rwlock.EnterReadLock();
entered = true;
s_logger.Info("Enter");
}
finally
{
if (entered) rwlock.ExitReadLock();
}
});
我是一名优秀的程序员,十分优秀!