Open In App

C# ReaderWriterLockSlim Class

Last Updated : 28 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

In C#, the ReaderWriterLockSlim class is present in the System.Threading namespace which is used to provide synchronization in a multithreaded environment. It allows multiple threads to read the resource concurrently, but only one thread can write at a time

Key Features:

  • More flexibility and optimization than the traditional ReaderWriterLock.
  • It is easy to use with recursion, simplifies the lock for reading or writing multiple times, and handles the possible deadlock conditions internally.
  • Provide an easier mechanism for upgrading and downgrading Locks.

Example: Use of ReaderWriterLockSlim to update the shared resource in a multithreaded environment.

C#
// Using ReaderWriterLockSlim in C#
using System;
using System.Threading;

class Geeks
{
	private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
	private static string res = "Initial Value";

	public static void Main()
	{
		Thread write = new Thread(Writer);
		Thread read1 = new Thread(Reader);
		Thread read = new Thread(Reader);

		write.Start();
		read1.Start();
		read.Start();

		write.Join();
		read1.Join();
		read.Join();
	}

	private static void Writer()
	{
		rwLock.EnterWriteLock();
		try
		{
			res = "Value is updated";
			Thread.Sleep(200); 
			Console.WriteLine("Performed written operation.");
		}
		finally
		{
			rwLock.ExitWriteLock();
		}
	}

	private static void Reader()
	{
		rwLock.EnterReadLock();
		try
		{
			Console.WriteLine("Shared Resource: " + res);
			Thread.Sleep(100); 
		}
		finally
		{
			rwLock.ExitReadLock();
		}
	}
}

Output
Performed written operation.
Shared Resource: Value is updated
Shared Resource: Value is updated

Explanation: In the above example, we use ReaderWriterLockSlim to perform read and write operations on the shared resource. We create two threads which perform the reading operation and one thread is performing the writing operation on the shared resource.


Constructor

Constructor

Description

ReaderWriterLockSlim()

This constructor creates a new instance of the ReaderWriterLockSlim class without the recursion.

ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy)

This constructor creates a new ReaderWriterLockSlim with the specified recursion policy.


Example: Initializing the ReaderWriterLockSlim with the ReaderWriterLockSlim(LockRecursionPolicy) constructor.

C#
// Initializing the ReaderWriterLockslim
// With the ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion) 
 
using System;
using System.Threading;

public class Geeks
{
    // Create a ReaderWriterLockSlim with recursion policy set to SupportsRecursion
    private static ReaderWriterLockSlim Lock = 
	new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

    // Shared resource to be read and written
    // Initial value is set to 0
    private static int c = 0;

    // Method to read the shared resource
    public static void ReadResource()
    {
        Lock.EnterReadLock();
        try
        {
            Console.WriteLine("Reading resource: " + c);
        }
        finally
        {
            Lock.ExitReadLock();
        }
    }

    // Method to write to the shared resource
    public static void WriteResource(int newValue)
    {
        Lock.EnterWriteLock();
        try
        {
            Console.WriteLine("Writing resource: " + newValue);
            c = newValue;
        }
        finally
        {
            Lock.ExitWriteLock();
        }
    }

    // Reader method that calls itself recursively
    public static void RecursiveRead(int count)
    {
        if (count > 0)
        {
            Lock.EnterReadLock();
            try
            {
                Console.WriteLine($"Recursively reading resource, count = {count}: " + c);

                // Call the method recursively
                RecursiveRead(count - 1);
            }
            finally
            {
                Lock.ExitReadLock();
            }
        }
    }

    public static void Main()
    {
        // Writing initial value to shared resource
        WriteResource(100);
        
        // Start multiple threads to simulate reading and recursion
        Thread read1 = new Thread(() => ReadResource());
        Thread read2 = new Thread(() => RecursiveRead(2));
        
        read1.Start();
        read2.Start();

        read1.Join();
        read2.Join();
        
        // Writing new value to 
        // shared resource
        WriteResource(200);
    }
}

Output
Writing resource: 100
Reading resource: 100
Recursively reading resource, count = 2: 100
Recursively reading resource, count = 1: 100
Writing resource: 200

Explanation: In the above example, we initialize a ReaderWriterLockSlim with the constructor ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy) which allows to use of lock recursively here we create a thread which is used to read the shared resource recursively.

Properties

Property

Description

IsReadLockHeld

This property checks whether the current thread holds a read lock or not.

IsUpgradeableReadLockHeld

It is used to check whether the current thread holds an upgradeable read lock or not.

IsWriteLockHeld

It is used to check the current thread holds a write lock.

RecursionPolicy

It is used to retrieve the recursion policy for the lock And check the lock can be reacquired recursively.

CurrentReadCount

Used to retrieve the number of threads that presently hold a read lock.

RecursiveReadCount

It returns the number of times the current thread has entered the read lock in recursion.

RecursiveUpgradeCount

This property is used to retrieve the number of times the current thread has entered the upgradeable read lock in recursive mode.

RecursiveWriteCount

It is used to retrieve the number of times the current thread has entered the write lock in recursive mode.

WaitingReadCount

Used to retrieve the number of threads which are currently waiting to enter the read lock.

WaitingUpgradeCount

This property retrieves the number of threads which are currently waiting to enter the upgradeable read lock.

WaitingWriteCount

This property is used to check the count of the number of threads that are waiting to enter the write lock.


Example: Using the IsReaderLockHeld and IsWriterLockHeld properties to check the lock's status during execution.

C#
using System;
using System.Threading;

class Geeks
{
    // Shared resource
    private static int val = 0;

    // Creating the ReaderWriterLockSlim object
    private static ReaderWriterLockSlim rwLock =
    new ReaderWriterLockSlim();

     // Read operation
    public static void Read()
    {
        // Entering the read lock
        rwLock.EnterReadLock();
        try
        {
            // Accessing shared resource (counter)
            Console.WriteLine($"Reader Thread {Thread.CurrentThread.ManagedThreadId} reading counter: {val}");
        }
        finally
        {
            // Releasing the read lock
            rwLock.ExitReadLock();
        }
    }

    // Write operation 
    public static void Write(int value)
    {
        // Entering the write lock (exclusive access)
        rwLock.EnterWriteLock();
        try
        {
            // Modifying shared resource (val)
            val = value;
            Console.WriteLine($"Writer Thread {Thread.CurrentThread.ManagedThreadId} updated counter to: {val}");
        }
        finally
        {
            // Releasing the write lock
            rwLock.ExitWriteLock();
        }
    }

    public static void Main()
    {
        // Creating reader threads
        Thread read = new Thread(Read);
        Thread read2 = new Thread(Read);
        Thread read3 = new Thread(Read);

        // Creating writer thread
        Thread write = new Thread(() => Write(3));

        // Starting threads
        read.Start();
        read2.Start();
        read3.Start();
        write.Start();

        // Waiting for all threads to finish
        read.Join();
        read2.Join();
        read3.Join();
        write.Join();

        // Checking lock status after the operations
        Console.WriteLine($"IsReaderLockHeld: {rwLock.IsReadLockHeld}");
        Console.WriteLine($"IsWriterLockHeld: {rwLock.IsWriteLockHeld}");
    }
}

Output
Writer Thread 6 updated counter to: 3
Reader Thread 4 reading counter: 3
Reader Thread 5 reading counter: 3
Reader Thread 3 reading counter: 3
IsReaderLockHeld: False
IsWriterLockHeld: False

Explanation: In the above example, we use the ReadWriterLockSlim class properties like IsReaderLockHeld which is used to check whether the status of the lock is completed or not, the output may be different each time because we are performing the multithreaded operations.

Methods

Method

Description

EnterReadLock()

This method is used to read the lock or block if necessary until the lock is available for the required.

TryEnterReadLock(TimeSpan timeout)

This method tries to acquire a read lock and we can specify a timeout period in the argument.

TryEnterReadLock(int millisecondsTimeout)

It is used to try to acquire a read lock within we can also specify the timeout timings in the argument in milliseconds.

EnterWriteLock()

This method takes a write lock, blocking if necessary until the lock is available.

TryEnterWriteLock(TimeSpan timeout)

This method acquires a write lock within the specified timeout period which we passed on the argument in milliseconds. If the lock cannot be acquired within the given time, it returns false.

TryEnterWriteLock(int millisecondsTimeout)

It tries to acquire a write lock in the specified timeout period in the argument in milliseconds. If the lock cannot be acquired within the given time, it returns false.

EnterUpgradeableReadLock()

This method takes control over the upgradeable read lock, Awaiting the lock acquisition.

TryEnterUpgradeableReadLock(TimeSpan timeout)

This method is used to take control over an upgradeable read lock within the specified timeout period.

TryEnterUpgradeableReadLock(int millisecondsTimeout)

Use to take control over an upgradeable read lock within the specified timeout period in milliseconds. If the lock cannot be acquired within the given time, it returns false.

ExitReadLock()

This method is used to free a read lock held by the current thread.

ExitWriteLock()

It is used to free a write lock which is held by the current thread.

ExitUpgradeableReadLock()

This method is used to release the upgradeable read lock held by the current thread.

Dispose()

It is used to free all resources used when the lock is no longer needed, to ensure that system resources are freed up.


Example: Using EnterReadLock(), TryEnterReadLock(int millisecondsTimeout), and EnterWriteLock() from the ReaderWriterLockSlim class.

C#
// Using methods of ReaderWriterLockSlim class in C#
using System;
using System.Threading;

class Geeks
{
    // Shared resource
    private static int res = 0;

    // Create ReaderWriterLockSlim instance
    private static ReaderWriterLockSlim rwLock = 
    new ReaderWriterLockSlim();

    // Method for reading
    public static void Read()
    {
        try
        {
            // Acquiring a read lock
            rwLock.EnterReadLock();
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} reading counter: {res}");
        }
        finally
        {
            // Releasing the read lock
            rwLock.ExitReadLock();
        }
    }

    // Method for trying to acquire read lock
    // With a timeout (using TryEnterReadLock)
    public static void TryReadWithTimeout()
    {
        // Attempting to acquire the read lock with 500ms timeout
        if (rwLock.TryEnterReadLock(500))
        {
            try
            {
                Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} successfully acquired read lock.");
                Console.WriteLine($"Counter value: {res}");
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }
        else
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} could not acquire read lock within timeout.");
        }
    }

    // Method for writing (using EnterWriteLock)
    public static void Write()
    {
        try
        {
            // Acquiring a write lock
            rwLock.EnterWriteLock();
            res++;
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} updated counter to: {res}");
        }
        finally
        {
            // Releasing the write lock
            rwLock.ExitWriteLock();
        }
    }

    public static void Main()
    {
        // Create and start threads for reading and writing
        Thread read1 = new Thread(Read);
        Thread read2 = new Thread(TryReadWithTimeout);
        Thread write = new Thread(Write);

        read1.Start();
        read2.Start();
        write.Start();

        read1.Join();
        read2.Join();
        write.Join();
    }
}

Output
Thread 5 updated counter to: 1
Thread 3 reading counter: 1
Thread 4 successfully acquired read lock.
Counter value: 1

Explanation: In the above example, we use EnterReadLock() method blocks until the read lock is available. It acquires the lock for the specified time which we pass 500 milliseconds and if it does not acquire the lock on the specified time then it will show the error message. And read the shared resource then we use the EnterWriteLock() which acquires the write lock updates the shared resource and then releases the lock.

Note: ReaderWriterLockSlim is not thread-abort safe. If threads accessing it can be aborted. The abort method is also obsoluted in the newer .NET versions.


Next Article
Article Tags :

Similar Reads