是否有一个ReaderWriterLockSlim等同于读者?

时间:2013-01-14 18:56:50

标签: c# .net multithreading concurrency readerwriterlockslim

我已经使用ReaderWriterLockSlim一段时间了,到目前为止我已经满足了我的需求。在我继续微调我的应用程序时,我发现ReaderWriterLockSlim对于我的用例来说略微不理想。

根据文献(和我的经验),它有利于作家而不是读者(即当读者和作家排队时,作家会得到偏好)。但是,我需要一个有利于读者的同等学历。我理解这种成分的副作用(特别是作家饥饿问题)。

是否有人可以指出的任何生产就绪的等价物?感谢。

1 个答案:

答案 0 :(得分:7)

根据MSDN,ReaderWriterLockSlim偏爱作家。这意味着当队列中有读者和作者时,作者会得到偏好。

这会导致读者饥饿,重现的测试代码为here。 我假设只有在写入是一个涉及线程上下文切换的长操作时才会发生饥饿。至少它总是在我的机器上复制,所以请告诉我我是不是错了。

另一方面,来自.net 2.0的ReaderWriterLock不会产生读者或作者的饥饿,代价是性能降低。 Here是以前样本中的修改代码,表明没有发生饥饿。

所以,回到你的问题 - 这取决于你需要RW Lock的功能。 递归锁定,异常处理,超时 - 最接近生产质量 RW锁定,支持上述所有,并且有利于读者可能是ReaderWriterLock。

此外,您可以采用描述first readers-writers problem的wiki文章中的代码,但当然您需要手动实现上述所有必需的功能,并且实现将有编写者饥饿问题。

Lock core可能看起来像这样:

class AutoDispose : IDisposable 
{ 
  Action _action; 
  public AutoDispose(Action action) 
  { 
    _action = action; 
  }
  public void Dispose()
  {
    _action();
  }
}

class Lock
{
  SemaphoreSlim wrt = new SemaphoreSlim(1);
  int readcount=0;

  public IDisposable WriteLock()
  {
    wrt.Wait();
    return new AutoDispose(() => wrt.Release());
  }

  public IDisposable ReadLock()
  {
    if (Interlocked.Increment(ref readcount) == 1)
        wrt.Wait();

    return new AutoDispose(() => 
    {
      if (Interlocked.Decrement(ref readcount) == 0)
         wrt.Release();
    });
  }
}

比较3个实现的性能,使用3个读取器和3个写入器线程,使用简单的内存中操作(使用长阻塞操作会导致RWLockSlim的读取器饥饿和自定义锁定的编写器饥饿):

Performance comparison

我确保工作负载循环不是由编译器展开的,但是我可能还有其他一些我不知道的陷阱,所以请仔细考虑这些测量结果。测试的源代码是here