当编写者尝试输入写锁定时,如何避免阻塞ReaderWriterLockSlim阅读器 [英] How to avoid blocking ReaderWriterLockSlim readers when writer is attempting to enter write lock

查看:63
本文介绍了当编写者尝试输入写锁定时,如何避免阻塞ReaderWriterLockSlim阅读器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ReaderWriterLockSlim 来保护某些操作.我希望读者优先于作家,这样当读者长时间持有该锁并且作家试图获取写锁时,以后的读者就不会受到作者的尝试的阻碍(如果发生这种情况,将会发生这种情况)编写者在 lock.EnterWriteLock())上被阻止.

I'm using ReaderWriterLockSlim to guard some operations. I would like to favor readers over writers, so that when a reader holds the lock for long and a writer is attempting to acquire the write lock, further readers down the road are not blocked by the writer's attempt (which is what would happen instead if the writer was blocked on lock.EnterWriteLock()).

为此,我虽然可以在较短的超时时间内使用 TryEnterWriteLock 来编写程序,但随后的读者仍可以在编写程序无法获得读锁的情况下使用它.但是,令我惊讶的是,我发现对 TryEnterWriteLock 的调用失败会更改锁的状态,无论如何都会阻止将来的读者.概念证明代码:

To this end, I though that the writer could use TryEnterWriteLock with a short timeout in a loop, so that subsequent readers would still be able to acquire the read lock while the writer can't. However, to my surprise, I found out that an unsuccessful call to TryEnterWriteLock changes the state of the lock, blocking future readers anyway. Proof of concept code:

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 看到类似的行为.

As you can see, even though thread 2 (the "Writer") hasn't acquired a writer lock and it's not in an EnterWriteLock call, thread 3 gets blocked for good. I can see a similar behavior with ReaderWriterLock.

我做错什么了吗?如果不是,当作家排队时,我必须采取什么选择来吸引读者?

Am I doing anything wrong? If not, what options do I have to favor readers when a writer is queued?

推荐答案

我无济于事,但我相信这是一个.NET Framework错误(更新:我有

I can’t help but I believe this is a .NET Framework bug (UPDATE: I have reported the bug). The following straightforward program (a simplified version of the above) illustrates that:

var myLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

var t1 = new Thread(() =>
{
    Console.WriteLine("T1:{0}: entering read lock...", DateTime.Now);
    myLock.EnterReadLock();
    Console.WriteLine("T1:{0}: ...entered read lock.", DateTime.Now);

    Thread.Sleep(50000);

    Console.WriteLine("T1:{0}: exiting", DateTime.Now);
    myLock.ExitReadLock();
});

var t2 = new Thread(() =>
{
    Thread.Sleep(1000);

    Console.WriteLine("T2:{0}: try-entering write lock...", DateTime.Now);
    bool result = myLock.TryEnterWriteLock(3000);
    Console.WriteLine("T2:{0}: ...try-entered write lock, result={1}.", DateTime.Now, result);

    Thread.Sleep(50000);

    if (result)
    {
        myLock.ExitWriteLock();
    }
    Console.WriteLine("T2:{0}: exiting", DateTime.Now);
});

var t3 = new Thread(() =>
{
    Thread.Sleep(2000);

    Console.WriteLine("T3:{0}: entering read lock...", DateTime.Now);
    myLock.EnterReadLock();
    Console.WriteLine("T3:{0}: ...entered read lock!!!!!!!!!!!!!!!!!!!", DateTime.Now);

    Thread.Sleep(50000);

    myLock.ExitReadLock();
    Console.WriteLine("T3:{0}: exiting", DateTime.Now);
});

t1.Start();
t2.Start();
t3.Start();

t1.Join();
t2.Join();
t3.Join();

以下情况以简单的顺序发生,没有锁车队,没有比赛,没有循环或其他任何事情.

The following happens in a simple order, no lock convoys, no races, no loops or anything.

  1. T1 获得读取锁.
  2. T2 试图获取写锁并阻塞,等待超时(因为 T1 持有该锁).
  3. T3 尝试获取一个读取锁并进行阻塞(因为 T2 被阻塞,等待写入锁,并且根据文档,这意味着所有其他读取器都被阻塞,直到超时).
  4. T2 的超时时间到期.根据文档,现在应该唤醒 T3 并获取读取锁.但是,这不会发生,并且 T3 将永远被阻止(或者,在本示例的情况下,在 T1 离开读取锁定之前的那50秒内).
  1. T1 acquires a read lock.
  2. T2 tries to acquire a write lock and blocks, waiting for a timeout (as T1 holds the lock).
  3. T3 tries to acquire a read lock and blocks (because T2 is blocked waiting for the write lock, and per the documentation, this means all further readers are blocked until timeouts).
  4. T2’s timeout expires. Per the documentation, T3 should now wake up and acquire the read lock. However, this does not happen and T3 is blocked forever (or, in the case of this example, for those 50 seconds until T1 leaves the read lock).

AFAICT,ExitMyLock L995"rel =" nofollow> ReaderWriterLockSlim WaitOnEvent 应该是 ExitAndWakeUpAppropriateWaiters .

AFAICT, the ExitMyLock in ReaderWriterLockSlim’s WaitOnEvent should have been ExitAndWakeUpAppropriateWaiters.

这篇关于当编写者尝试输入写锁定时,如何避免阻塞ReaderWriterLockSlim阅读器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆