Есть ли эквивалент ReaderWriterLockSlim, который благоприятствует читателям? - программирование
Подтвердить что ты не робот

Есть ли эквивалент ReaderWriterLockSlim, который благоприятствует читателям?

Я использовал ReaderWriterLockSlim в течение некоторого времени, и он удовлетворил мои потребности до этого момента. По мере того как я продолжаю настраивать свое приложение, я обнаружил, что ReaderWriterLockSlim немного субоптимален для моего варианта использования.

В документации (и моем опыте), это способствует писателям над читателями (т.е. когда читатели и писатели стоят в очереди, писатели получат предпочтение). Тем не менее, мне нужен эквивалент, который благоприятствует читателям. Я понимаю побочные эффекты такого компонента (в частности, проблема голода писателя).

Есть ли какие-либо готовые к производству эквиваленты, на которые кто-то может указать? Спасибо.

4b9b3361

Ответ 1

Согласно MSDN, ReaderWriterLockSlim поддерживает авторов. Это означает, что когда в очереди появятся читатели и писатели, писатели получат предпочтение.

Это может вызвать голод читателя, тестовый код для воспроизведения этого здесь. Я предполагаю, что голодание может произойти только в том случае, если запись является длительной операцией, включающей переключатель контекста потока. По крайней мере, он всегда воспроизводится на моей машине, поэтому, пожалуйста, скажите мне, если я ошибаюсь.

С другой стороны, ReaderWriterLock от .net 2.0 не производит ни чтения, ни голода писателя, за счет снижения производительности. Здесь изменен код из предыдущего образца, чтобы показать, что голодания не происходит.

Итак, вернемся к вашему вопросу - это зависит от того, какие функции вы требуете от блокировки RW. Рекурсивные блокировки, обработка исключений, тайм-ауты - самое близкое соответствие производителю RW-контролю качества, которое поддерживает все вышеперечисленное, и, возможно, предпочтения читателей, вероятно, будут ReaderWriterLock.

Также вы можете принять код из wiki-статьи, описывающий первую проблему читателей-писателей, но, конечно, вам нужно будет реализовать все необходимые функции сверху вручную, и реализация будет иметь проблемы с голоданием писателя.

Блокировка ядра может выглядеть примерно так:

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

Я убедился, что компилятор не разворачивает цикл рабочей нагрузки, но могут быть другие ошибки, о которых я не знаю, поэтому сделайте эти измерения с помощью соли. Исходный код для тестов здесь.