其实ReaderWriterLockSlim的实现前段时间看了,当时不打算记录下来的,因为它的实现实在System.Core项目里面,而不是mscorlib项目。按照惯例我们还是先看看网上的一些说法吧。

读写锁 ReaderWriterLock 、就是支持单个写线程和多个读线程的锁。自.NET 3.5 开始 ReaderWriterLockSlim登上舞台,ReaderWriterLockSlim 可以看做是 ReaderWriterLock 的升级版。 由于 ReaderWriterLockSlim 默认不支持递归调用、所以在某种意义上来说更不容易造成死锁。
ReaderWriterLockSlim 类支持三种锁定模式:Read,Write,UpgradeableRead。这三种模式对应的方法分别是 EnterReadLock,EnterWriteLock,EnterUpgradeableReadLock 。再就是与此对应的 TryEnterReadLock,TryEnterWriteLock,TryEnterUpgradeableReadLock,ExitReadLock,ExitWriteLock,ExitUpgradeableReadLock。Read 和 Writer 锁定模式比较简单易懂:Read 模式是典型的共享锁定模式,任意数量的线程都可以在该模式下同时获得锁;Writer 模式则是互斥模式,在该模式下只允许一个线程进入该锁。UpgradeableRead 锁定模式可能对于大多数人来说比较新鲜,但是在数据库领域却众所周知。
备注及注意事项
1、对于同一把锁、多个线程可同时进入读模式。
2、对于同一把锁、同时只允许一个线程进入写模式。
3、对于同一把锁、同时只允许一个线程进入可升级的读模式。
4、通过默认构造函数创建的读写锁是不支持递归的,若想支持递归 可通过构造 ReaderWriterLockSlim(LockRecursionPolicy) 创建实例。
5、对于同一把锁、同一线程不可两次进入同一锁状态(开启递归后可以)
6、对于同一把锁、即便开启了递归、也不可以在进入读模式后再次进入写模式或者可升级的读模式(在这之前必须退出读模式)。
7、再次强调、不建议启用递归。
8、读写锁具有线程关联性,即两个线程间拥有的锁的状态相互独立不受影响、并且不能相互修改其锁的状态。
9、升级状态:在进入可升级的读模式 EnterUpgradeableReadLock后,可在恰当时间点通过EnterWriteLock进入写模式。
10、降级状态:可升级的读模式可以降级为读模式:即在进入可升级的读模式EnterUpgradeableReadLock后, 通过首先调用读取模式EnterReadLock方法,然后再调用 ExitUpgradeableReadLock 方法。

实现code如下:

public enum LockRecursionPolicy
{
NoRecursion = ,
SupportsRecursion = ,
}
internal class ReaderWriterCount
{
public long lockID;
public int readercount;
public int writercount;
public int upgradecount;
public ReaderWriterCount next;
} public class ReaderWriterLockSlim : IDisposable
{
//Specifying if the lock can be reacquired recursively.
bool fIsReentrant;
int myLock; //The variables controlling spinning behavior of Mylock(which is a spin-lock)
const int LockSpinCycles = ;
const int LockSpinCount = ;
const int LockSleep0Count = ; // These variables allow use to avoid Setting events (which is expensive) if we don't have to.
uint numWriteWaiters; // maximum number of threads that can be doing a WaitOne on the writeEvent
uint numReadWaiters; // maximum number of threads that can be doing a WaitOne on the readEvent
uint numWriteUpgradeWaiters; // maximum number of threads that can be doing a WaitOne on the upgradeEvent (at most 1).
uint numUpgradeWaiters; //Variable used for quick check when there are no waiters.
bool fNoWaiters; int upgradeLockOwnerId;
int writeLockOwnerId; // conditions we wait on.
EventWaitHandle writeEvent; // threads waiting to acquire a write lock go here.
EventWaitHandle readEvent; // threads waiting to acquire a read lock go here (will be released in bulk)
EventWaitHandle upgradeEvent; // thread waiting to acquire the upgrade lock
EventWaitHandle waitUpgradeEvent; // thread waiting to upgrade from the upgrade lock to a write lock go here (at most one) // Every lock instance has a unique ID, which is used by ReaderWriterCount to associate itself with the lock
// without holding a reference to it.
static long s_nextLockID;
long lockID; // See comments on ReaderWriterCount.
[ThreadStatic]
static ReaderWriterCount t_rwc; bool fUpgradeThreadHoldingRead; private const int MaxSpinCount = ; //The uint, that contains info like if the writer lock is held, num of readers etc.
uint owners; private const uint WRITER_HELD = 0x80000000;
private const uint WAITING_WRITERS = 0x40000000;
private const uint WAITING_UPGRADER = 0x20000000; private const uint MAX_READER = 0x10000000 - 2;
private const uint READER_MASK = 0x10000000 - ;
private bool fDisposed; public ReaderWriterLockSlim() : this(LockRecursionPolicy.NoRecursion){} public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy)
{
if (recursionPolicy == LockRecursionPolicy.SupportsRecursion)
{
fIsReentrant = true;
}
InitializeThreadCounts();
fNoWaiters = true;
lockID = Interlocked.Increment(ref s_nextLockID);
} private void InitializeThreadCounts()
{
upgradeLockOwnerId = -1;
writeLockOwnerId = -1;
} public void EnterReadLock()
{
TryEnterReadLock(-1);
} public bool TryEnterReadLock(int millisecondsTimeout)
{
return TryEnterReadLock(new TimeoutTracker(millisecondsTimeout));
} private bool TryEnterReadLock(TimeoutTracker timeout)
{
bool result = false;
try
{
result = TryEnterReadLockCore(timeout);
}
finally
{
}
return result;
} private bool TryEnterReadLockCore(TimeoutTracker timeout)
{
if(fDisposed)
throw new ObjectDisposedException(null); ReaderWriterCount lrwc = null;
int id = Thread.CurrentThread.ManagedThreadId; if (!fIsReentrant)
{
if (id == writeLockOwnerId)
{
//Check for AW->AR
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_ReadAfterWriteNotAllowed));
}
EnterMyLock();
lrwc = GetThreadRWCount(false); //Check if the reader lock is already acquired. Note, we could check the presence of a reader by not allocating rwc (But that would lead to two lookups in the common case. It's better to keep a count in the struucture).
if (lrwc.readercount > )
{
ExitMyLock();
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveReadNotAllowed));
}
else if (id == upgradeLockOwnerId)
{
//The upgrade lock is already held.Update the global read counts and exit. lrwc.readercount++;
owners++;
ExitMyLock();
return true;
}
}
else
{
EnterMyLock();
lrwc = GetThreadRWCount(false);
if (lrwc.readercount > )
{
lrwc.readercount++;
ExitMyLock();
return true;
}
else if (id == upgradeLockOwnerId)
{
//The upgrade lock is already held. Update the global read counts and exit.
lrwc.readercount++;
owners++;
ExitMyLock();
fUpgradeThreadHoldingRead = true;
return true;
}
else if (id == writeLockOwnerId)
{
//The write lock is already held.Update global read counts here,
lrwc.readercount++;
owners++;
ExitMyLock();
return true;
}
} bool retVal = true;
int spincount = ; for (; ; )
{
// We can enter a read lock if there are only read-locks have been given out and a writer is not trying to get in.
if (owners < MAX_READER)
{
// Good case, there is no contention, we are basically done
owners++; // Indicate we have another reader
lrwc.readercount++;
break;
} if (spincount < MaxSpinCount)
{
ExitMyLock();
if (timeout.IsExpired)
return false;
spincount++;
SpinWait(spincount);
EnterMyLock();
//The per-thread structure may have been recycled as the lock is acquired (due to message pumping), load again.
if(IsRwHashEntryChanged(lrwc))
lrwc = GetThreadRWCount(false);
continue;
} // Drat, we need to wait. Mark that we have waiters and wait.
if (readEvent == null) // Create the needed event
{
LazyCreateEvent(ref readEvent, false);
if (IsRwHashEntryChanged(lrwc))
lrwc = GetThreadRWCount(false);
continue; // since we left the lock, start over.
} retVal = WaitOnEvent(readEvent, ref numReadWaiters, timeout);
if (!retVal)
{
return false;
}
if (IsRwHashEntryChanged(lrwc))
lrwc = GetThreadRWCount(false);
} ExitMyLock();
return retVal;
} private void EnterMyLock()
{
if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0)
EnterMyLockSpin();
} private void EnterMyLockSpin()
{
int pc = Environment.ProcessorCount;
for (int i = ; ; i++)
{
if (i < LockSpinCount && pc > )
{
Thread.SpinWait(LockSpinCycles * (i + )); // Wait a few dozen instructions to let another processor release lock.
}
else if (i < (LockSpinCount + LockSleep0Count))
{
Thread.Sleep(); // Give up my quantum.
}
else
{
Thread.Sleep(); // Give up my quantum.
} if (myLock == && Interlocked.CompareExchange(ref myLock, , ) == )
return;
}
} private void ExitMyLock()
{
Debug.Assert(myLock != , "Exiting spin lock that is not held");
Volatile.Write(ref myLock, );
}
/// DontAllocate is set to true if the caller just wants to get an existing entry for this thread, but doesn't want to add one if an existing one could not be found.
private ReaderWriterCount GetThreadRWCount(bool dontAllocate)
{
ReaderWriterCount rwc = t_rwc;
ReaderWriterCount empty = null;
while (rwc != null)
{
if (rwc.lockID == this.lockID)
return rwc; if (!dontAllocate && empty == null && IsRWEntryEmpty(rwc))
empty = rwc; rwc = rwc.next;
} if (dontAllocate)
return null; if (empty == null)
{
empty = new ReaderWriterCount();
empty.next = t_rwc;
t_rwc = empty;
} empty.lockID = this.lockID;
return empty;
} private static bool IsRWEntryEmpty(ReaderWriterCount rwc)
{
if (rwc.lockID == )
return true;
else if (rwc.readercount == && rwc.writercount == && rwc.upgradecount == )
return true;
else
return false;
} public void ExitReadLock()
{
ReaderWriterCount lrwc = null;
EnterMyLock();
lrwc = GetThreadRWCount(true);
if (lrwc == null || lrwc.readercount < )
{
//You have to be holding the read lock to make this call.
ExitMyLock();
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedRead));
} if (fIsReentrant)
{
if (lrwc.readercount > )
{
lrwc.readercount--;
ExitMyLock();
return;
} if (Thread.CurrentThread.ManagedThreadId == upgradeLockOwnerId)
{
fUpgradeThreadHoldingRead = false;
}
}
--owners;
lrwc.readercount--;
ExitAndWakeUpAppropriateWaiters();
} private void ExitAndWakeUpAppropriateWaiters()
{
if (fNoWaiters)
{
ExitMyLock();
return;
} ExitAndWakeUpAppropriateWaitersPreferringWriters();
} public void EnterWriteLock()
{
TryEnterWriteLock(-1);
}
public bool TryEnterWriteLock(int millisecondsTimeout)
{
return TryEnterWriteLock(new TimeoutTracker(millisecondsTimeout));
} private bool TryEnterWriteLock(TimeoutTracker timeout)
{
bool result = false;
try
{
result = TryEnterWriteLockCore(timeout);
}
finally
{
}
return result;
} private bool TryEnterWriteLockCore(TimeoutTracker timeout)
{
if(fDisposed)
throw new ObjectDisposedException(null); int id = Thread.CurrentThread.ManagedThreadId;
ReaderWriterCount lrwc;
bool upgradingToWrite = false; if (!fIsReentrant)
{
if (id == writeLockOwnerId)
{
//Check for AW->AW
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveWriteNotAllowed));
}
else if (id == upgradeLockOwnerId)
{
//AU->AW case is allowed once.
upgradingToWrite = true;
} EnterMyLock();
lrwc = GetThreadRWCount(true); //Can't acquire write lock with reader lock held.
if (lrwc != null && lrwc.readercount > )
{
ExitMyLock();
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_WriteAfterReadNotAllowed));
}
}
else
{
EnterMyLock();
lrwc = GetThreadRWCount(false);
if (id == writeLockOwnerId)
{
lrwc.writercount++;
ExitMyLock();
return true;
}
else if (id == upgradeLockOwnerId)
{
upgradingToWrite = true;
}
else if (lrwc.readercount > )
{
//Write locks may not be acquired if only read locks have been acquired.
ExitMyLock();
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_WriteAfterReadNotAllowed));
}
}
int spincount = ;
bool retVal = true;
for (; ; )
{
if (IsWriterAcquired())
{
// Good case, there is no contention, we are basically done
SetWriterAcquired();
break;
} //Check if there is just one upgrader, and no readers.Assumption: Only one thread can have the upgrade lock, so the following check will fail for all other threads that may sneak in when the upgrading thread is waiting. if (upgradingToWrite)
{
uint readercount = GetNumReaders();
if (readercount == )
{
//Good case again, there is just one upgrader, and no readers.
SetWriterAcquired(); // indicate we have a writer.
break;
}
else if (readercount == )
{
if (lrwc != null)
{
if (IsRwHashEntryChanged(lrwc))
lrwc = GetThreadRWCount(false); if (lrwc.readercount > )
{
//Good case again, there is just one upgrader, and no readers.
SetWriterAcquired(); // indicate we have a writer.
break;
}
}
}
} if (spincount < MaxSpinCount)
{
ExitMyLock();
if (timeout.IsExpired)
return false;
spincount++;
SpinWait(spincount);
EnterMyLock();
continue;
} if (upgradingToWrite)
{
if (waitUpgradeEvent == null) // Create the needed event
{
LazyCreateEvent(ref waitUpgradeEvent, true);
continue; // since we left the lock, start over.
}
retVal = WaitOnEvent(waitUpgradeEvent, ref numWriteUpgradeWaiters, timeout); //The lock is not held in case of failure.
if (!retVal)
return false;
}
else
{
// Drat, we need to wait. Mark that we have waiters and wait.
if (writeEvent == null) // create the needed event.
{
LazyCreateEvent(ref writeEvent, true);
continue; // since we left the lock, start over.
} retVal = WaitOnEvent(writeEvent, ref numWriteWaiters, timeout);
//The lock is not held in case of failure.
if (!retVal)
return false;
}
} if (fIsReentrant)
{
if (IsRwHashEntryChanged(lrwc))
lrwc = GetThreadRWCount(false);
lrwc.writercount++;
} ExitMyLock();
writeLockOwnerId = id;
return true;
} public void ExitWriteLock()
{
ReaderWriterCount lrwc;
if (!fIsReentrant)
{
if (Thread.CurrentThread.ManagedThreadId != writeLockOwnerId)
{
//You have to be holding the write lock to make this call.
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedWrite));
}
EnterMyLock();
}
else
{
EnterMyLock();
lrwc = GetThreadRWCount(false); if (lrwc == null)
{
ExitMyLock();
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedWrite));
} if (lrwc.writercount < )
{
ExitMyLock();
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedWrite));
} lrwc.writercount--; if (lrwc.writercount > )
{
ExitMyLock();
return;
}
} ClearWriterAcquired(); writeLockOwnerId = -1; ExitAndWakeUpAppropriateWaiters();
} public void EnterUpgradeableReadLock()
{
TryEnterUpgradeableReadLock(-);
} private bool TryEnterUpgradeableReadLock(TimeoutTracker timeout)
{
bool result = false;
try
{
result = TryEnterUpgradeableReadLockCore(timeout);
}
finally
{
}
return result;
} private bool TryEnterUpgradeableReadLockCore(TimeoutTracker timeout)
{
if(fDisposed)
throw new ObjectDisposedException(null); int id = Thread.CurrentThread.ManagedThreadId;
ReaderWriterCount lrwc; if (!fIsReentrant)
{
if (id == upgradeLockOwnerId)
{
//Check for AU->AU
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveUpgradeNotAllowed));
}
else if (id == writeLockOwnerId)
{
//Check for AU->AW
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterWriteNotAllowed));
} EnterMyLock();
lrwc = GetThreadRWCount(true);
//Can't acquire upgrade lock with reader lock held.
if (lrwc != null && lrwc.readercount > )
{
ExitMyLock();
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterReadNotAllowed));
}
}
else
{
EnterMyLock();
lrwc = GetThreadRWCount(false); if (id == upgradeLockOwnerId)
{
lrwc.upgradecount++;
ExitMyLock();
return true;
}
else if (id == writeLockOwnerId)
{
//Write lock is already held, Just update the global state to show presence of upgrader.
Debug.Assert((owners & WRITER_HELD) > );
owners++;
upgradeLockOwnerId = id;
lrwc.upgradecount++;
if (lrwc.readercount > )
fUpgradeThreadHoldingRead = true;
ExitMyLock();
return true;
}
else if (lrwc.readercount > )
{
//Upgrade locks may not be acquired if only read locks have been acquired.
ExitMyLock();
throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterReadNotAllowed));
}
} bool retVal = true;
int spincount = ; for (; ; )
{
//Once an upgrade lock is taken, it's like having a reader lock held
//until upgrade or downgrade operations are performed. if ((upgradeLockOwnerId == -) && (owners < MAX_READER))
{
owners++;
upgradeLockOwnerId = id;
break;
} if (spincount < MaxSpinCount)
{
ExitMyLock();
if (timeout.IsExpired)
return false;
spincount++;
SpinWait(spincount);
EnterMyLock();
continue;
} // Drat, we need to wait. Mark that we have waiters and wait.
if (upgradeEvent == null) // Create the needed event
{
LazyCreateEvent(ref upgradeEvent, true);
continue; // since we left the lock, start over.
} //Only one thread with the upgrade lock held can proceed.
retVal = WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, timeout);
if (!retVal)
return false;
} if (fIsReentrant)
{
//The lock may have been dropped getting here, so make a quick check to see whether some other
//thread did not grab the entry.
if (IsRwHashEntryChanged(lrwc))
lrwc = GetThreadRWCount(false);
lrwc.upgradecount++;
} ExitMyLock();
return true;
} public void ExitUpgradeableReadLock()
{
ReaderWriterCount lrwc;
if (!fIsReentrant)
{
if (Thread.CurrentThread.ManagedThreadId != upgradeLockOwnerId)
{
//You have to be holding the upgrade lock to make this call.
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedUpgrade));
}
EnterMyLock();
}
else
{
EnterMyLock();
lrwc = GetThreadRWCount(true); if (lrwc == null)
{
ExitMyLock();
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedUpgrade));
} if (lrwc.upgradecount < )
{
ExitMyLock();
throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedUpgrade));
} lrwc.upgradecount--; if (lrwc.upgradecount > )
{
ExitMyLock();
return;
}
fUpgradeThreadHoldingRead = false;
} owners--;
upgradeLockOwnerId = -1; ExitAndWakeUpAppropriateWaiters();
} private void ExitAndWakeUpAppropriateWaitersPreferringWriters()
{
bool setUpgradeEvent = false;
bool setReadEvent = false;
uint readercount = GetNumReaders(); //We need this case for EU->ER->EW case, as the read count will be 2 in that scenario.
if (fIsReentrant)
{
if (numWriteUpgradeWaiters > && fUpgradeThreadHoldingRead && readercount == )
{
ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
waitUpgradeEvent.Set(); // release all upgraders (however there can be at most one).
return;
}
} if (readercount == && numWriteUpgradeWaiters > )
{
//We have to be careful now, as we are droppping the lock. No new writes should be allowed to sneak in if an upgrade was pending.
ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
waitUpgradeEvent.Set(); // release all upgraders (however there can be at most one).
}
else if (readercount == && numWriteWaiters > )
{
ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
writeEvent.Set(); // release one writer.
}
else if (readercount >= )
{
if (numReadWaiters != || numUpgradeWaiters != )
{
if (numReadWaiters != )
setReadEvent = true; if (numUpgradeWaiters != && upgradeLockOwnerId == -)
{
setUpgradeEvent = true;
} ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock) if (setReadEvent)
readEvent.Set(); // release all readers. if (setUpgradeEvent)
upgradeEvent.Set(); //release one upgrader.
}
else
ExitMyLock();
}
else
ExitMyLock();
} private void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent)
{
ExitMyLock();
EventWaitHandle newEvent;
if (makeAutoResetEvent)
newEvent = new AutoResetEvent(false);
else
newEvent = new ManualResetEvent(false);
EnterMyLock();
if (waitEvent == null) // maybe someone snuck in.
waitEvent = newEvent;
else
newEvent.Close();
} private bool IsRwHashEntryChanged(ReaderWriterCount lrwc)
{
return lrwc.lockID != this.lockID;
} private bool IsWriterAcquired()
{
return (owners & ~WAITING_WRITERS) == ;
}
private void SetWriterAcquired()
{
owners |= WRITER_HELD; // indicate we have a writer.
} private bool WaitOnEvent(EventWaitHandle waitEvent, ref uint numWaiters, TimeoutTracker timeout)
{
waitEvent.Reset();
numWaiters++;
fNoWaiters = false; //Setting these bits will prevent new readers from getting in.
if (numWriteWaiters == )
SetWritersWaiting();
if (numWriteUpgradeWaiters == )
SetUpgraderWaiting(); bool waitSuccessful = false;
ExitMyLock(); // Do the wait outside of any lock try
{
waitSuccessful = waitEvent.WaitOne(timeout.RemainingMilliseconds);
}
finally
{
EnterMyLock();
--numWaiters; if (numWriteWaiters == && numWriteUpgradeWaiters == && numUpgradeWaiters == && numReadWaiters == )
fNoWaiters = true; if (numWriteWaiters == )
ClearWritersWaiting();
if (numWriteUpgradeWaiters == )
ClearUpgraderWaiting(); if (!waitSuccessful) // We may also be aboutto throw for some reason. Exit myLock.
ExitMyLock();
}
return waitSuccessful;
} private uint GetNumReaders()
{
return owners & READER_MASK;
} public int CurrentReadCount
{
get
{
int numreaders = (int)GetNumReaders(); if (upgradeLockOwnerId != -)
return numreaders - ;
else
return numreaders;
}
}
private struct TimeoutTracker
{
private int m_total;
private int m_start;
public TimeoutTracker(TimeSpan timeout)
{
long ltm = (long)timeout.TotalMilliseconds;
if (ltm < - || ltm > (long)Int32.MaxValue)
throw new ArgumentOutOfRangeException("timeout");
m_total = (int)ltm;
if (m_total != - && m_total != )
m_start = Environment.TickCount;
else
m_start = ;
} public TimeoutTracker(int millisecondsTimeout)
{
if (millisecondsTimeout < -)
throw new ArgumentOutOfRangeException("millisecondsTimeout");
m_total = millisecondsTimeout;
if (m_total != - && m_total != )
m_start = Environment.TickCount;
else
m_start = ;
} public int RemainingMilliseconds
{
get
{
if (m_total == - || m_total == )
return m_total; int elapsed = Environment.TickCount - m_start;
// elapsed may be negative if TickCount has overflowed by 2^31 milliseconds.
if (elapsed < || elapsed >= m_total)
return ;
return m_total - elapsed;
}
} public bool IsExpired
{
get
{
return RemainingMilliseconds == ;
}
}
}
}

ReaderWriterLockSlim的默认够着函数是不支持递归的,EnterReadLock的核心方法是TryEnterReadLockCore,TryEnterReadLockCore方法的实现也比较简单,首先进入自己的锁,然后获取自己ReaderWriterCount实例,因为一般情况下我们的reader都不会到达上限,所以直接 把ReaderWriterCount的readercount加1,owners++; 然后退出锁,返回成功,如果是递归调用就要复杂一点了。ExitReadLock也是非常简单,一样是进入自己的锁,找到ReaderWriterCount实例,执行--owners;lrwc.readercount--; 在退出自己的锁,到这里我们知道共享锁的一个实现实例。

EnterWriteLock 的实现核心是TryEnterWriteLockCore方法,TryEnterWriteLockCore方法因为只有一个线程可以进入,所以有点不一样,不考虑递归也是先进入锁的模式,查找ReaderWriterCount实例,然后执行if (IsWriterAcquired()){SetWriterAcquired();break;}【当前申请读锁成功,一般是没有这个好的情况的哦】,实际更多情况都会执行到retVal = WaitOnEvent(writeEvent, ref numWriteWaiters, timeout);等待锁,最后记录锁的id ,writeLockOwnerId = id; ExitWriteLock的实现 writeLockOwnerId = -1,然后在ExitAndWakeUpAppropriateWaiters

EnterUpgradeableReadLock的实现核心是TryEnterUpgradeableReadLockCore方法,也是进入锁模式,获取ReaderWriterCount实例,如果当前没有升级锁则 执行【owners++;upgradeLockOwnerId = id;】,否者就只有等待了retVal = WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, timeout);  ExitUpgradeableReadLock的实现【 owners--;upgradeLockOwnerId = -1;】最后调用ExitAndWakeUpAppropriateWaiters, ExitAndWakeUpAppropriateWaiters这个方法就是检查是否有锁与需要重置信号。

在这里也实现了不用lock来实现lock的效果:

  int myLock;
private void EnterMyLock()
{
if (Interlocked.CompareExchange(ref myLock, , ) != )
EnterMyLockSpin();
} private void EnterMyLockSpin()
{
int pc = Environment.ProcessorCount;
for (int i = ; ; i++)
{
if (i < LockSpinCount && pc > )
{
Thread.SpinWait(LockSpinCycles * (i + )); // Wait a few dozen instructions to let another processor release lock.
}
else if (i < (LockSpinCount + LockSleep0Count))
{
Thread.Sleep(); // Give up my quantum.
}
else
{
Thread.Sleep(); // Give up my quantum.
} if (myLock == && Interlocked.CompareExchange(ref myLock, , ) == )
return;
}
}
private void ExitMyLock()
{
Debug.Assert(myLock != , "Exiting spin lock that is not held");
Volatile.Write(ref myLock, );
}

C# ReaderWriterLockSlim 实现的更多相关文章

  1. 多线程中的锁系统(二)-volatile、Interlocked、ReaderWriterLockSlim

    上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了,本篇主要介绍下升级锁和原子操作. 阅读目录 volatile Interlocked ReaderWriterLo ...

  2. 异步与并行~ReaderWriterLockSlim实现的共享锁和互斥锁

    返回目录 在System.Threading.Tasks命名空间下,使用ReaderWriterLockSlim对象来实现多线程并发时的锁管理,它比lock来说,性能更好,也并合理,我们都知道lock ...

  3. C#读写锁ReaderWriterLockSlim的使用

    读写锁的概念很简单,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁.在C#中,推荐使用ReaderWriterLockSlim类来完成读写锁的功能. 某些场合下,对 ...

  4. 让C#轻松实现读写锁分离--封装ReaderWriterLockSlim

    ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...

  5. 锁ReaderWriterLockSlim介绍

    概述 ReaderWriterLockSlim 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问: 常用的方法: cacheLock.EnterReadLock();//加上读取锁 ...

  6. 读写锁ReaderWriterLockSlim

    读写锁的概念很简单,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁. 某些场合下,对一个对象的读取次数远远大于修改次数,如果只是简单的用lock方式加锁,则会影响读 ...

  7. 封装ReaderWriterLockSlim

    封装ReaderWriterLockSlim ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLoc ...

  8. 并发数据(锁)ReaderWriterLockSlim

    ReaderWriterLockSlim 类 ReaderWriterLockSlim 类支持三种锁定模式:Read,Write,UpgradeableRead.这三种模式对应的方法分别是 Enter ...

  9. 关于最优化读写,测试各个加锁:Lock、安全字典、信号量、ReaderWriterLock、ReaderWriterLockSlim

    大家对于自身项目中都有本地缓存的逻辑,但这块的读写何种机制下哪个快,哪个慢,需要测试对比,以下测试报告,期望给大家一个借鉴,如果有更好的测试结果也欢迎大家一起讨论. 以下测试是开启10个并发任务对同一 ...

  10. 第十三节:实际开发中使用最多的监视锁Monitor、lock语法糖的扩展、混合锁的使用(ManualResetEvent、SemaphoreSlim、ReaderWriterLockSlim)

    一. 监视锁(Monitor和lock) 1. Monitor类,限定线程个数的一把锁,两个核心方法: Enter:锁住某个资源. Exit:退出某一个资源. 测试案例:开启5个线程同时对一个变量进行 ...

随机推荐

  1. kafka其中一台节点坏掉的迁移或者数据迁移

    kafka版本:适用于目前2.0以下 第一步: 假如有一个topic叫做test,当前topic的详情是这样的: [cdh@cdh1 kafka_2.11-1.0.1]$ bin/kafka-topi ...

  2. HDU4185 Oil Skimming 二分图匹配 匈牙利算法

    原文链接http://www.cnblogs.com/zhouzhendong/p/8231146.html 题目传送门 - HDU4185 题意概括 每次恰好覆盖相邻的两个#,不能重复,求最大覆盖次 ...

  3. BZOJ1208 [HNOI2004]宠物收养所 splay

    原文链接http://www.cnblogs.com/zhouzhendong/p/8085803.html 题目传送门 - BZOJ1208 题意概括 有两种数,依次加入. 规则为下: 如果当前剩余 ...

  4. springboot(@Service,@Mapper)注解失效导致无法注入service和mapper

    给我来灵感的博客:感谢:http://blog.51cto.com/xingej/2053297?utm_source=oschina-app 因为使用了注解的类在使用时是通过new出来的,导致注解注 ...

  5. Python enum 枚举 判断 key(键) 或者 value(值)是否在枚举中

    Python enum 枚举 判断 key(键) 或者 value(值)是否在枚举中 python 的基本用法请浏览:https://www.cnblogs.com/ibingshan/p/98564 ...

  6. 整合django和bootstrap框架

    环境: python版本:2.7.8 django版本:1.7.1 bootstrap版本:3.3.0 首先github上面有两个开源的项目用来整合django和bootstrap. https:// ...

  7. 剑指offer 1,输入一个字符串,将字符串的空格替换成%20

    剑指offer 1,输入一个字符串,将字符串的空格替换成%20    function replaceSpace(str){      return str.replace(/\s/g,"% ...

  8. CentOS 7开机出现welcome to emergency mode! 解决方法

    CentOS7.3昨天用的还好好的的,但是今天开机提示如下(如图提示):welcome to emergency mode!after logging in ,type “journalctl -xb ...

  9. Springboot 1.5.x 集成基于Centos7的RabbitMQ集群安装及配置

    RabbitMQ简介 RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件). RabbitMQ是一套开源(MPL)的消息队列服务软件,是由LShift提供的一 ...

  10. SpringMVC(十一) RequestMapping获取Cookie值

    可以在控制器方法中使用类似@CookieValue("JSESSIONID") String sessionID的方式,来获取请求中的Cookie的值. 样例控制器代码 packa ...