2009-03-04 17 views
3

Basit (yükseltmeler veya zaman aşımları yok) ReaderWriterLock for Silverlight'ın bir adopted uygulamasına sahibim, Tasarım konusunda iyi veya kötü olup olmadığını doğru uzmanlığa sahip herkesin doğrulayabileceğini merak ediyordum. Bana göre oldukça iyi görünüyor, reklamı yapılan gibi çalışıyor, ancak çok iş parçacıklı kodla sınırlı deneyimim var. Iyi ise Silverlight şu anda kilidin bir okuyucu-yazıcı türünü yoksun olarakSilverlight ReaderWriterLock Uygulaması İyi/Kötü?

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); 
      } 
     } 

    } 

} 

, çok başkalarına yararlı olabilir. Teşekkürler.

cevap

4

Ben (x86 seviyesine kadar) (.NET 3.5 ReaderWriterLockSlim olmuştur) Vance Morrison's ReaderWriterLockon my blog açıklamaya derinlemesine gidin. Bu, tasarımınızda yararlı olabilir, özellikle şeylerin gerçekten nasıl çalıştığını anlamak.

+0

Hey, yazdığın için ve Vance Morrison'un uygulamasına işaret ettiğin için teşekkürler. Aslında, onun uygulanmasını en az değişiklikle Silverlight'ta çalıştırdım ve süper hızlı da çalışıyor. Blogumda bunu geri çevirmek için birkaç numara ekleyeceğim. Şerefe. –

1

IsReadorLockHeld ve IsWriterLockHeld yöntemlerinin her ikisi de kavramsal bir düzeyde kusurludur. Belirli bir noktada belirli bir kilitin tutulduğunu veya tutulmadığını belirlemek mümkün olsa da, kilidi tutmaya devam etmedikçe (kodunuzda geçerli değildir) bu bilgiler olmadan güvenle yapabileceğiniz hiçbir şey yoktur.

Bu yöntemler daha doğru bir şekilde WasReadLockHeldInThePast ve WasWriterLockHeldInThePast olarak adlandırılacaktır. Yöntemleri, yaptıkları şeyin daha doğru bir temsiline yeniden adlandırdığınızda, bunların çok kullanışlı olmadıkları daha net hale gelir.

+0

Haklısınız, aktif tüketicinin dışındaki kullanım bir “sonradan gelen” cevabı olurdu, bu yüzden kullanışlı değil. Hem Is..Held işlevlerini kaldıracağım, teşekkürler. –

0

Bu sınıf benim için daha basit görünüyor ve aynı işlevselliği sağlıyor. Her zaman PulsesAll() olduğu için biraz daha az performans gösterebilir, ancak mantığın anlaşılması çok daha kolaydır ve performans isabetinin bu kadar büyük olduğundan şüphe duyuyorum.

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

Tatlı görünüyor ve yorumlar gerçekten yardımcı oluyor. Ve Silverlight için, performansın bu örnekte bir sorun olduğunu düşünmüyorum, ama yine de kontrol edeceğim. Teşekkürler, bu konuda çok çabuklar. :) –

+0

Teşekkürler! Jeff Moser'ın cevabını daha çok seviyorum. :) – grieve