2009-03-04 2 views
3

Silverlight 용 간단한 (업그레이드 또는 시간 초과 없음) ReaderWriterLock의 구현이 adopted인데, 설계 상으로는 좋거나 나쁘면 올바른 전문 지식을 가진 사람이 확인할 수 있는지 궁금합니다. 나에게 그것은 꽤 괜찮아 보인다. 광고되는 것처럼 작동하지만, 나는 멀티 스레딩 코드에 대한 경험이 제한적이다. 이 좋은 경우에 실버 라이트가 현재 잠금의 리더 라이터 타입 부족으로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); 
      } 
     } 

    } 

} 

, 너무 다른 사람에게 도움이 될 수 있습니다. 감사.

답변

4

나는 (은 x86 수준까지) (.NET 3.5 ReaderWriterLockSlim되었다) Vance Morrison's ReaderWriterLockon my blog 설명에 깊이 이동합니다. 이것은 설계에 유용 할 수 있습니다. 특히 사물이 실제로 어떻게 작동하는지 이해하는 것이 좋습니다.

+0

Vance Morrison의 구현에 대해 알려 주시고 저에게 알려 주셔서 감사합니다. 실제로 Silverlight에서 최소한의 변경만으로 구현 된 구현을 얻었으며 너무 빠르게 실행됩니다. 나는 나의 blog에 그것을 되 돌리는 약간의 수를 내놓을 것이다. 건배. –

1

IsReadorLockHeld 및 IsWriterLockHeld 메서드 모두 개념적으로 결함이 있습니다. 특정 시점에서 특정 잠금이 유지되거나 유지되지 않는다는 것을 결정할 수는 있지만 잠금을 계속 유지하지 않는 한이 정보없이 안전하게 수행 할 수있는 것은 없습니다 (코드에는 해당되지 않음).

이러한 메서드는 더 정확하게 WasReadLockHeldInThePast 및 WasWriterLockHeldInThePast로 명명됩니다. 메소드의 이름을 더 정확하게 표현하면 메소드가 매우 유용하지 않다는 것이 명확 해집니다.

+0

당신이 맞습니다. 활성 소비자 이외의 사용법은 "사후"응답 일 것이므로 유용하지 않습니다. Is ..Held 함수를 모두 제거합니다. 감사합니다. –

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의 경우 성능을 많이 고려하지 않지만이 인스턴스에서는 문제를 확인하려고 노력하겠습니다. 고마워, 너는 이것으로 아주 빨랐어. :) –

+0

고마워요! 그래도 Jeff Moser의 대답은 더 좋아. :) – grieve