2009-03-04 2 views
3

У меня есть реализация adopted простой (без обновлений или тайм-аутов) ReaderWriterLock для Silverlight, мне было интересно, кто из тех, кто имеет право, может проверить, хорошо ли это или плохо по дизайну. Для меня это выглядит довольно хорошо, он работает как рекламируемый, но у меня ограниченный опыт использования многопоточного кода как такового.Silverlight ReaderWriterLock Реализация Хорошо/Плохо?

public sealed class ReaderWriterLock 
{ 
    private readonly object syncRoot = new object(); // Internal lock. 
    private int i = 0;         // 0 or greater means readers can pass; -1 is active writer. 
    private int readWaiters = 0;      // Readers waiting for writer to exit. 
    private int writeWaiters = 0;      // Writers waiting for writer lock. 
    private ConditionVariable conditionVar;    // Condition variable. 

    public ReaderWriterLock() 
    { 
     conditionVar = new ConditionVariable(syncRoot); 
    } 

    /// <summary> 
    /// Gets a value indicating if a reader lock is held. 
    /// </summary> 
    public bool IsReaderLockHeld 
    { 
     get 
     { 
      lock (syncRoot) 
      { 
       if (i > 0) 
        return true; 
       return false; 
      } 
     } 
    } 

    /// <summary> 
    /// Gets a value indicating if the writer lock is held. 
    /// </summary> 
    public bool IsWriterLockHeld 
    { 
     get 
     { 
      lock (syncRoot) 
      { 
       if (i < 0) 
        return true; 
       return false; 
      } 
     } 
    } 

    /// <summary> 
    /// Aquires the writer lock. 
    /// </summary> 
    public void AcquireWriterLock() 
    { 
     lock (syncRoot) 
     { 
      writeWaiters++; 
      while (i != 0) 
       conditionVar.Wait();  // Wait until existing writer frees the lock. 
      writeWaiters--; 
      i = -1;    // Thread has writer lock. 
     } 
    } 

    /// <summary> 
    /// Aquires a reader lock. 
    /// </summary> 
    public void AcquireReaderLock() 
    { 
     lock (syncRoot) 
     { 
      readWaiters++; 
      // Defer to a writer (one time only) if one is waiting to prevent writer starvation. 
      if (writeWaiters > 0) 
      { 
       conditionVar.Pulse(); 
       Monitor.Wait(syncRoot); 
      } 
      while (i < 0) 
       Monitor.Wait(syncRoot); 
      readWaiters--; 
      i++; 
     } 
    } 

    /// <summary> 
    /// Releases the writer lock. 
    /// </summary> 
    public void ReleaseWriterLock() 
    { 
     bool doPulse = false; 
     lock (syncRoot) 
     { 
      i = 0; 
      // Decide if we pulse a writer or readers. 
      if (readWaiters > 0) 
      { 
       Monitor.PulseAll(syncRoot); // If multiple readers waiting, pulse them all. 
      } 
      else 
      { 
       doPulse = true; 
      } 
     } 
     if (doPulse) 
      conditionVar.Pulse();      // Pulse one writer if one waiting. 
    } 

    /// <summary> 
    /// Releases a reader lock. 
    /// </summary> 
    public void ReleaseReaderLock() 
    { 
     bool doPulse = false; 
     lock (syncRoot) 
     { 
      i--; 
      if (i == 0) 
       doPulse = true; 
     } 
     if (doPulse) 
      conditionVar.Pulse();      // Pulse one writer if one waiting. 
    } 

    /// <summary> 
    /// Condition Variable (CV) class. 
    /// </summary> 
    public class ConditionVariable 
    { 
     private readonly object syncLock = new object(); // Internal lock. 
     private readonly object m;      // The lock associated with this CV. 

     public ConditionVariable(object m) 
     { 
      lock (syncLock) 
      { 
       this.m = m; 
      } 
     } 

     public void Wait() 
     { 
      bool enter = false; 
      try 
      { 
       lock (syncLock) 
       { 
        Monitor.Exit(m); 
        enter = true; 
        Monitor.Wait(syncLock); 
       } 
      } 
      finally 
      { 
       if (enter) 
        Monitor.Enter(m); 
      } 
     } 

     public void Pulse() 
     { 
      lock (syncLock) 
      { 
       Monitor.Pulse(syncLock); 
      } 
     } 

     public void PulseAll() 
     { 
      lock (syncLock) 
      { 
       Monitor.PulseAll(syncLock); 
      } 
     } 

    } 

} 

Если это хорошо, это может быть полезным для других тоже, как Silverlight в настоящее время отсутствует тип читателя писатель блокировки. Благодарю.

ответ

4

Я иду в глубину на объяснении Vance Morrison's ReaderWriterLock (который стал ReaderWriterLockSlim в .NET 3.5) on my blog (вплоть до уровня x86). Это может быть полезно в вашем дизайне, особенно для понимания того, как все работает.

+0

Эй, спасибо за ваше письмо и указывая на реализацию Vance Morrison. На самом деле, я получил его реализацию на Silverlight с минимальными изменениями, и он тоже работает очень быстро. Я буду выкладывать некоторые цифры, чтобы вернуться в мой блог. Приветствия. – 2009-03-05 21:19:47

1

Оба метода IsReadorLockHeld и IsWriterLockHeld ошибочны на концептуальном уровне. Хотя можно определить, что в данный момент времени определен или заблокирован какой-либо конкретный замок, абсолютно ничего нельзя безопасно обойтись без этой информации, если вы не продолжаете удерживать блокировку (не в случае вашего кода).

Эти методы будут более точно названы WasReadLockHeldInThePast и WasWriterLockHeldInThePast. Как только вы переименуете методы в более точное представление о том, что они делают, становится понятным, что они не очень полезны.

+0

Вы правы, использование вне активного потребителя было бы ответом «после факта», поэтому это не полезно. Спасибо, я удалю обе функции Is..Held. – 2009-03-05 20:46:58

0

Этот класс кажется мне более простым и обеспечивает ту же функциональность. Это может быть немного менее впечатляющим, так как он всегда PulsesAll(), но логика гораздо проще понять, и я сомневаюсь, что производительность удалась.

public sealed class ReaderWriterLock() 
{ 
    private readonly object internalLock = new object(); 
    private int activeReaders = 0; 
    private bool activeWriter = false; 

    public void AcquireReaderLock() 
    { 
     lock (internalLock) 
     { 
      while (activeWriter) 
       Monitor.Wait(internalLock); 
      ++activeReaders; 
     } 
    } 

    public void ReleaseReaderLock() 
    { 
     lock (internalLock) 
     { 
      // if activeReaders <= 0 do some error handling 
      --activeReaders; 
      Monitor.PulseAll(internalLock); 
     } 
    } 

    public void AcquireWriterLock() 
    { 
     lock (internalLock) 
     { 
      // first wait for any writers to clear 
      // This assumes writers have a higher priority than readers 
      // as it will force the readers to wait until all writers are done. 
      // you can change the conditionals in here to change that behavior. 
      while (activeWriter) 
       Monitor.Wait(internalLock); 

      // There are no more writers, set this to true to block further readers from acquiring the lock 
      activeWriter = true; 

      // Now wait till all readers have completed. 
      while (activeReaders > 0) 
       Monitor.Wait(internalLock); 

      // The writer now has the lock 
     } 
    } 

    public void ReleaseWriterLock() 
    { 
     lock (internalLock) 
     { 
      // if activeWriter != true handle the error 
      activeWriter = false; 
      Monitor.PulseAll(internalLock); 
     } 
    } 
} 
+0

Выглядит мило, и комментарии действительно помогают. И для Silverlight я не думаю, что производительность - это большая проблема в этом случае, хотя я попытаюсь проверить. Спасибо, ты очень быстро с этим справился. :) – 2009-03-05 20:50:56

+0

Спасибо! Тем не менее, мне нравится ответ Джеффа Мозера. :) – grieve

Смежные вопросы