[英]Difference in usage and implementation of ManualResetEvent(Slim), Semaphore(Slim) and ReaderWriterLock(Slim)
[英]Silverlight ReaderWriterLock Implementation Good/Bad?
我為 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 目前缺少讀寫器類型的鎖。 謝謝。
我 go 在我的博客上深入解釋了Vance Morrison 的 ReaderWriterLock (在 .NET 3.5 中成為 ReaderWriterLockSlim)(下至 Z8A9DA7865483C5FD359F3ACEF178D26D 級別) 這可能對您的設計有所幫助,尤其是了解事物的實際運作方式。
您的 IsReadorLockHeld 和 IsWriterLockHeld 方法在概念層面都有缺陷。 雖然可以確定在給定的時間點是否持有特定的鎖,但如果沒有這些信息,您絕對不能安全地做任何事情,除非您繼續持有鎖(代碼中不是這種情況)。
這些方法將更准確地命名為 WasReadLockHeldInThePast 和 WasWriterLockHeldInThePast。 一旦您將方法重命名為更准確地表示它們所做的事情,就會清楚地表明它們不是很有用。
這個 class 對我來說似乎更簡單,並提供相同的功能。 它的性能可能稍差一些,因為它總是 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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.