Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






TheReaderWriterLockSlim Class

It is common to have threads simply read the contents of some data. If this data is protected by a mutual exclusive lock (like the SimpleSpinLock, SimpleWaitLock, SimpleHybridLock, Another­ HybridLock, SpinLock, Mutex, or Monitor), then if multiple threads attempt this access concur- rently, only one thread gets to run and all the other threads are blocked, which can reduce scalability and throughput in your application substantially. However, if all the threads want to access the data in a read-only fashion, then there is no need to block them at all; they should all be able to access the data concurrently. On the other hand, if a thread wants to modify the data, then this thread needs exclusive access to the data. The ReaderWriterLockSlim construct encapsulates the logic to solve this problem. Specifically, the construct controls threads like this:

■ When one thread is writing to the data, all other threads requesting access are blocked.

 

■ When one thread is reading from the data, other threads requesting read access are allowed to continue executing, but threads requesting write access are blocked.

■ When a thread writing to the data has completed, either a single writer thread is unblocked so it can access the data or all the reader threads are unblocked so that all of them can access

the data concurrently. If no threads are blocked, then the lock is free and available for the next reader or writer thread that wants it.

■ When all threads reading from the data have completed, a single writer thread is unblocked so it can access the data. If no threads are blocked, then the lock is free and available for the next reader or writer thread that wants it.

Here is what this class looks like (some method overloads are not shown).

 

public class ReaderWriterLockSlim : IDisposable {

public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy); public void Dispose();

 

public void EnterReadLock();

public Boolean TryEnterReadLock(Int32 millisecondsTimeout); public void ExitReadLock();

 

public void EnterWriteLock();

public Boolean TryEnterWriteLock(Int32 millisecondsTimeout); public void ExitWriteLock();

 

// Most applications will never query any of these properties public Boolean IsReadLockHeld { get; }

public Boolean IsWriteLockHeld { get; }

public Int32 CurrentReadCount { get; } public Int32 RecursiveReadCount { get; } public Int32 RecursiveWriteCount { get; } public Int32 WaitingReadCount { get; }

public Int32 WaitingWriteCount { get; }


public LockRecursionPolicy RecursionPolicy { get; }

// Members related to upgrading from a reader to a writer not shown

}

 

Here is some code that demonstrates the use of this construct.

 

internal sealed class Transaction : IDisposable { private readonly ReaderWriterLockSlim m_lock =

new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); private DateTime m_timeOfLastTrans;

 

public void PerformTransaction() { m_lock.EnterWriteLock();



// This code has exclusive access to the data... m_timeOfLastTrans = DateTime.Now; m_lock.ExitWriteLock();

}

 

public DateTime LastTransaction { get {

m_lock.EnterReadLock();

// This code has shared access to the data... DateTime temp = m_timeOfLastTrans; m_lock.ExitReadLock();

return temp;

}

}

 

public void Dispose() { m_lock.Dispose(); }

}

 

There are a few concepts related to this construct that deserve special mention. First, Reader­ WriterLockSlim’s constructor allows you to pass in a LockRecursionPolicy flag, which is defined as follows.

 

public enum LockRecursionPolicy { NoRecursion, SupportsRecursion }

 

If you pass the SupportsRecursion flag, then the lock will add thread ownership and recursion behaviors to the lock. As discussed earlier in this chapter, these behaviors negatively affect the lock’s performance, so I recommend that you always pass LockRecursionPolicy.NoRecursion to the constructor (as I’ve done). For a reader-writer lock, supporting thread ownership and recursion is phe- nomenally expensive, because the lock must keep track of all the reader threads that it has let into the lock and keep a separate recursion count for each reader thread. In fact, to maintain all this informa- tion in a thread-safe way, the ReaderWriterLockSlim internally uses a mutually exclusive spinlock! No, I’m not kidding.

The ReaderWriterLockSlim class offers additional methods (not shown earlier) that allow a reading thread to upgrade itself to a writer thread. Later, the thread can downgrade itself to a reader thread. The thinking here is that a thread could start reading the data and based on the data’s con- tents, the thread might want to modify the data. To do this, the thread would upgrade itself from a reader to a writer. Having the lock support this behavior deteriorates the lock’s performance, and I don’t think that this is a useful feature at all. Here’s why: a thread can’t just turn itself from a reader


into a writer. Other threads may be reading, too, and these threads will have to exit the lock com- pletely before the thread trying to upgrade is allowed to become a writer. This is the same as having the reader thread exit the lock and then immediately acquire it for writing.

       
   
 
 

 

 


Date: 2016-03-03; view: 758


<== previous page | next page ==>
TheMonitor Class and Sync Blocks | TheOneManyLock Class
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.006 sec.)