Click here to Skip to main content
15,867,704 members
Articles / Programming Languages / C#
Tip/Trick

The Simplest Implementation of a Reader-Writer Lock for .NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
24 Jan 2022CPOL1 min read 10.5K   156   12   10
An implementation of a basic Reader-Writer lock using only the System.Threading.Monitor class
The article shows how you can create a simple synchronization primitive that restricts access to a shared resource to a single writer, while still allowing multiple readers to access it simultaneously. Of course, it's not supposed to replace the highly optimized default ReaderWriterLockSlim implementation, but nonetheless, it's a very interesting demonstration of how Monitor.Wait and Monitor.PulseAll can be used to achieve the goal.

Introduction

The standard Monitor.Wait and Monitor.PulseAll methods are rarely used today, but still could provide powerful capabilities for thread synchronization. As mentioned, we're going to implement a standard Reader-Writer lock, so let's dive into the code straight away:

C#
private readonly object syncRoot = new object();
private readonly object syncWrite = new object();

// A number of acive readers.
private int rcount = 0;

// A total number of pending and active writers.
private int wcount = 0;

That's right, all we need is two counters - one for each owner type and two root objects for synchronization. Next, let's explore the EnterXXXLock sections:

C#
public void EnterReadLock()
{
    lock (syncRoot)
    {
        while (wcount > 0)
        {
            Monitor.Wait(syncRoot); // Wait till all writers are done.
        }

        rcount++; // Notify that there is an active reader.
    }
}

public void EnterWriteLock()
{
    lock (syncRoot)
    {
        wcount++; // Notify that there is a pending writer.

        while (rcount > 0)
        {
            Monitor.Wait(syncRoot); // Wait till all readers are done.
        }
    }

    Monitor.Enter(syncWrite);
}

The EnterReadLock method allows the reader to continue only when the resource is not being accessed by writers. The EnterWriteLock method, in turn, immediately notifies the presence of the writer, and then waits until readers release the lock. Technically, this code splits incoming requests into two large groups of writers and readers, with the former taking precedence. Therefore, we need an extra call to Monitor.Enter(syncWrite) to ensure that only one writer can access at a given time. The following release logic:

C#
public void ExitReadLock()
{
    lock (syncRoot)
    {
        if (--rcount == 0 && wcount > 0)
        {
            Monitor.PulseAll(syncRoot); // Notify writers waiting.
        }
    }
}

public void ExitWriteLock()
{
    Monitor.Exit(syncWrite);

    lock (syncRoot)
    {
        if (--wcount == 0)
        {
            Monitor.PulseAll(syncRoot); // Notify readers waiting.
        }
    }
}

The last reader or writer in a row just wakes up all waiting threads so they can continue the race. To demonstrate how this works, I've created a console application that runs multiple threads accessing the same resource at the same time. That's the sample output generated by the app:

The source code is available for download at this link. Just un-zip it and execute the dotnet run command.

History

  • 23rd January, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Belarus Belarus
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Suggestion2 things Pin
Paulo Zemek23-Jan-22 21:32
mvaPaulo Zemek23-Jan-22 21:32 
GeneralRe: 2 things Pin
ryanovic23-Jan-22 22:00
ryanovic23-Jan-22 22:00 
GeneralRe: 2 things Pin
Paulo Zemek23-Jan-22 22:10
mvaPaulo Zemek23-Jan-22 22:10 
I see... reader count is the number of ACTIVE readers, while writer count is the number of pending writers. Got it. I would just suggest giving more proper names then... aside from that, it's only about some typos in the article. Overall very good.

GeneralRe: 2 things Pin
ryanovic23-Jan-22 22:16
ryanovic23-Jan-22 22:16 
QuestionsyncWrite Pin
Сергій Ярошко23-Jan-22 20:45
professionalСергій Ярошко23-Jan-22 20:45 
AnswerRe: syncWrite Pin
ryanovic23-Jan-22 22:02
ryanovic23-Jan-22 22:02 
GeneralRe: syncWrite Pin
Сергій Ярошко24-Jan-22 18:37
professionalСергій Ярошко24-Jan-22 18:37 
GeneralRe: syncWrite Pin
ryanovic24-Jan-22 21:39
ryanovic24-Jan-22 21:39 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA23-Jan-22 20:25
professionalȘtefan-Mihai MOGA23-Jan-22 20:25 
GeneralRe: My vote of 5 Pin
ryanovic23-Jan-22 22:18
ryanovic23-Jan-22 22:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.