Gab*_*ini 9 .net multithreading readerwriterlockslim
我正在ReaderWriterLockSlim用来保护一些操作.我想赞成读者而不是作家,这样当读者长时间持有锁并且作家试图获得写锁时,未来的读者也不会被作者的尝试所阻挡(如果是这样的话会发生这种情况.作家被封锁了lock.EnterWriteLock()).
为此,我虽然编写器可以TryEnterWriteLock在循环中使用短暂的超时,以便后续的读者仍然能够获得读锁定而编写者不能.然而,令我惊讶的是,我发现一个不成功的呼叫TryEnterWriteLock改变了锁的状态,无论如何阻止了未来的读者.概念证明代码:
System.Threading.ReaderWriterLockSlim myLock = new System.Threading.ReaderWriterLockSlim(System.Threading.LockRecursionPolicy.NoRecursion);
System.Threading.Thread t1 = new System.Threading.Thread(() =>
{
Console.WriteLine("T1:{0}: entering read lock...", DateTime.Now);
myLock.EnterReadLock();
Console.WriteLine("T1:{0}: ...entered read lock.", DateTime.Now);
System.Threading.Thread.Sleep(10000);
});
System.Threading.Thread t2 = new System.Threading.Thread(() =>
{
System.Threading.Thread.Sleep(1000);
while (true)
{
Console.WriteLine("T2:{0}: try-entering write lock...", DateTime.Now);
bool result = myLock.TryEnterWriteLock(TimeSpan.FromMilliseconds(1500));
Console.WriteLine("T2:{0}: ...try-entered write lock, result={1}.", DateTime.Now, result);
if (result)
{
// Got it!
break;
}
System.Threading.Thread.Yield();
}
System.Threading.Thread.Sleep(9000);
});
System.Threading.Thread t3 = new System.Threading.Thread(() =>
{
System.Threading.Thread.Sleep(2000);
Console.WriteLine("T3:{0}: entering read lock...", DateTime.Now);
myLock.EnterReadLock();
Console.WriteLine("T3:{0}: ...entered read lock!!!!!!!!!!!!!!!!!!!", DateTime.Now);
System.Threading.Thread.Sleep(8000);
});
Run Code Online (Sandbox Code Playgroud)
此代码的输出是:
T1:18-09-2015 16:29:49: entering read lock...
T1:18-09-2015 16:29:49: ...entered read lock.
T2:18-09-2015 16:29:50: try-entering write lock...
T3:18-09-2015 16:29:51: entering read lock...
T2:18-09-2015 16:29:51: ...try-entered write lock, result=False.
T2:18-09-2015 16:29:51: try-entering write lock...
T2:18-09-2015 16:29:53: ...try-entered write lock, result=False.
T2:18-09-2015 16:29:53: try-entering write lock...
T2:18-09-2015 16:29:54: ...try-entered write lock, result=False.
T2:18-09-2015 16:29:54: try-entering write lock...
T2:18-09-2015 16:29:56: ...try-entered write lock, result=False.
T2:18-09-2015 16:29:56: try-entering write lock...
T2:18-09-2015 16:29:57: ...try-entered write lock, result=False.
T2:18-09-2015 16:29:57: try-entering write lock...
T2:18-09-2015 16:29:59: ...try-entered write lock, result=False.
T2:18-09-2015 16:29:59: try-entering write lock...
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,即使线程2("Writer")没有获得写入锁定而且它不在EnterWriteLock调用中,线程3 也会被阻止.我可以看到类似的行为ReaderWriterLock.
我做错了吗?如果没有,当作家排队时,我有什么选择支持读者?
我可以\xe2\x80\x99t 提供帮助,但我相信这是一个 .NET Framework 错误(更新:我已报告该错误)。以下简单的程序(上述程序的简化版本)说明了这一点:
\n\nvar myLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);\n\nvar t1 = new Thread(() =>\n{\n Console.WriteLine("T1:{0}: entering read lock...", DateTime.Now);\n myLock.EnterReadLock();\n Console.WriteLine("T1:{0}: ...entered read lock.", DateTime.Now);\n\n Thread.Sleep(50000);\n\n Console.WriteLine("T1:{0}: exiting", DateTime.Now);\n myLock.ExitReadLock();\n});\n\nvar t2 = new Thread(() =>\n{\n Thread.Sleep(1000);\n\n Console.WriteLine("T2:{0}: try-entering write lock...", DateTime.Now);\n bool result = myLock.TryEnterWriteLock(3000);\n Console.WriteLine("T2:{0}: ...try-entered write lock, result={1}.", DateTime.Now, result);\n\n Thread.Sleep(50000);\n\n if (result)\n {\n myLock.ExitWriteLock();\n }\n Console.WriteLine("T2:{0}: exiting", DateTime.Now);\n});\n\nvar t3 = new Thread(() =>\n{\n Thread.Sleep(2000);\n\n Console.WriteLine("T3:{0}: entering read lock...", DateTime.Now);\n myLock.EnterReadLock();\n Console.WriteLine("T3:{0}: ...entered read lock!!!!!!!!!!!!!!!!!!!", DateTime.Now);\n\n Thread.Sleep(50000);\n\n myLock.ExitReadLock();\n Console.WriteLine("T3:{0}: exiting", DateTime.Now);\n});\n\nt1.Start();\nt2.Start();\nt3.Start();\n\nt1.Join();\nt2.Join();\nt3.Join();\nRun Code Online (Sandbox Code Playgroud)\n\n以下内容以简单的顺序发生,没有锁车队,没有竞赛,没有循环或任何东西。
\n\nT1获取读锁。T2尝试获取写锁并阻塞,等待超时(如T1持有锁)。T3尝试获取读锁并阻塞(因为T2被阻塞等待写锁,并且根据文档,这意味着所有其他读取器都被阻塞直到超时)。T2\xe2\x80\x99s 超时到期。根据文档,T3现在应该唤醒并获取读锁。然而,这种情况不会发生,并且T3会被永远阻塞(或者,在本示例中,在T1离开读锁之前的 50 秒内)。AFAICT,\xe2\x80\x99sExitMyLock中的应该是.ReaderWriterLockSlimWaitOnEventExitAndWakeUpAppropriateWaiters