ReaderWriterLockSlim Class in C# Threading

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

  • ReaderWriterLockSlim(LockRecursionPolicy): The constructor used to specifying the lock recursion policy and to initialize a new instance of the ReaderWriterLockSlim class.

  • ReaderWriterLockSlim: This is the default constructor of the ReaderWriterLockSlim class for initializing a new instance of the class.

Properties

  • CurrentReadCount: It is used to get the total number of unique threads that have entered the lock in read mode.
  • IsReadLockHeldThis property get  a value which points whether the current thread has entered the lock in read mode.
  • IsWriteLockHeldThis 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

img1.gif


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.

Up Next
    Ebook Download
    View all
    Learn
    View all