Introduction
ReaderWriterLockSlim class is new to
.Net Framework 3.5 and is a replacement for the older
ReaderWriterLock class.
Problem with ReaderWriterLock
The problem with
ReaderWriterLock is with its
implementation. Several experts have slammed this technique and found that
outside of limited scenarios, it is actually far slower than the
Monitor.Enter method used to get an exclusive lock.
ReaderWriterLock gives higher
priority to reader threads than writers. This makes sense if you have many
readers and only a few writers. So a lot of readers are able to read the
resource while the writer has to wait longer to get the lock. But what If you
have equal or more writers. The process of favoring readers make writer threads
queued up and take a very long time to complete.
To solve all issues related to the
ReaderWriterLock class, the .Net
Framework 3.5 introduces the new class
ReaderWriterLockSlim.
ReaderWriterLockSlim class
Namespace: System.Threading
This namespace provides all methods and properties the class needs to implement the ReaderWriterLockSlim class.
Assembly: System.Core (in System.Core.dll)
Constructors
Properties
-
CurrentReadCount: It is used to get the
total number of unique threads that have entered the lock in read mode.
- IsReadLockHeld: This property get a value which points whether the current thread has entered the lock
in read mode.
-
IsWriteLockHeld: This property get a value which points whether the current thread has entered the lock in write mode.
-
RecursiveWriteCount: This property get the
number of times the current thread has entered the lock in write mode, which point to the recursion.
-
WaitingReadCount: This property is used to get the
total number of threads which are waiting to enter the lock in read mode.
-
WaitingWriteCount: This property is used to get the
total number of threads which are waiting to enter the lock in write mode.
Method
- Dispose:
This method is used to free all resources used by the current instance of the
ReaderWriterLockSlim class.
- EnterReadLock: This method is used to enter the lock in read mode.
- EnterWriteLock: This method is used to enter the lock in write mode.
- ExitReadLock: Free the recursion count for read mode, and exits read mode if the
resulting count is 0 (zero).
- ExitWriteLock: Free the recursion count for write mode, and exits write mode if the
resulting count is 0 (zero).
- TryEnterReadLock(TimeSpan):
This method is used enter the lock in read mode, with an optional time-out.
- TryEnterWriteLock(TimeSpan): This method is used enter the lock in write mode, with an optional time-out.
ReaderWriterLockSlim is used
to protect a resource which is read by multiple threads and written to by one
thread at a time.
ReaderWriterLockSlim
allows multiple threads to be in read mode, allows one thread to be in write
mode with exclusive ownership of the lock, and allows one thread that has read
access to be in upgradeable read mode, from which the thread can upgrade to
write mode without having to relinquish its read access to the resource.
A thread can enter the lock in three modes.
- Read mode
- Write mode
- upgradeable read mode
and has the methods
EnterReadLock,
EnterWriteLock,EnterUpgradeableReadLock,
and corresponding TryEnterXXLock and ExitXXLock methods, that do what you'd
expect. Read and Write are easy and should be familiar: Read is a typical shared
lock mode, where any number of threads can acquire the lock in the Read mode
simultaneously, and Write is a mutual exclusion mode, where no other threads are
permitted to simultaneously hold the lock in any mode. The
UpgradeableReadLock will probably be
new to most people, though it's a concept that's well known to database folks,
and is the magic that allows us to fix the upgrade problem I mentioned earlier.
We'll look at it more closely in a moment.
To use the ReaderWriterLockSlim, it's a simple
matter of creating a lock for your class.
ReaderWriterLockSlim
rwls = new
ReaderWriterLockSlim();
and then wrapping all read or write operations
between Enter{Read,Write}Lock and Exit{Read,Write}Lock methods.
private void
ReadTest()
{
m_Lock.EnterReadLock();
// access the shared state for reading here
m_Lock.ExitReadLock();
}
private void
WriteTest()
{
m_Lock.EnterWriteLock();
// access the shared state for writing here
m_Lock.ExitWriteLock();
}
In the
following code, three threads
continually enumerate a list, while two further threads append a random number
to the list every second. A read lock protects the list readers and a write lock
protects the list writers:
using
System;
using
System.Collections.Generic;
using
System.Threading;
namespace
ReaderWriterLockSlim_class
{
class akshay
{
static
ReaderWriterLockSlim rw = new
ReaderWriterLockSlim();
static
List<int> items =
new List<int>();
static
Random rand = new
Random();
static void
Main()
{
new
Thread(Read).Start();
new
Thread(Read).Start();
new
Thread(Read).Start();
new
Thread(Write).Start("A");
new
Thread(Write).Start("B");
Console.Read();
}
static void
Read()
{
while (true)
{
rw.EnterReadLock();
foreach (int
i in items) Thread.Sleep(10);
rw.ExitReadLock();
}
}
static void
Write(object threadID)
{
while (true)
{
int newNumber = GetRandNum(50);
rw.EnterWriteLock();
items.Add(newNumber);
rw.ExitWriteLock();
Console.WriteLine("Thread
" + threadID + " added " + newNumber);
Thread.Sleep(100);
}
}
static int
GetRandNum(int max)
{
lock (rand)
return rand.Next(max);
}
}
}
Output
ReaderWriterLockSlim has managed thread affinity;
that is, each Thread object must make its own method calls to enter and exit
lock modes. No thread can change the mode of another thread.
Resources
Here some useful related resources.