【发布时间】:2015-09-18 14:38:02
【问题描述】:
我正在使用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);
});
这段代码的输出是:
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...
如您所见,即使线程 2(“写入器”)尚未获得写入器锁且不在 EnterWriteLock 调用中,线程 3 也会被永久阻塞。我可以看到ReaderWriterLock 的类似行为。
我做错了吗?如果不是,当作家排队时,我必须有哪些选择来支持读者?
【问题讨论】:
-
有趣。看来,如果您改用
TryEnterWriteLock(0)(并将超时移动到下面某处的Sleep),它可以正常工作(至少在这里)。但是,根据我对documentation 的阅读,它的行为不应该是这样的:“尝试进入读取模式或可升级模式的其他线程会阻塞,直到所有等待进入写入模式的线程都已超时或进入写入模式,然后退出”. -
将循环添加到线程
t3,您将获得成功。t3尝试在t2尝试发生超时写入时发生读取锁定。 -
@Mormegil 它的行为如文档中所述。当
t2超时等待时,t3尝试发生读锁。 -
@Hamlet, t2 超时,因此根据文档,“尝试进入读取模式的其他线程”应该被解除阻塞,但事实并非如此。
-
将 t3 的 Thread.Sleep 更改为 3000 将不起作用,因为您试图在循环中发生 writelook。但是使用 TryEnterReadLock(int) 会解决你的问题。
标签: .net multithreading readerwriterlockslim