Using ReaderWriterLock over Monitor for Thread Locking

By | August 14, 2011

If you are looking for Multi-Threaded application, you must have already tried our very old lock statement (synclock in VB.NET). The lock statement is the most common practice to make certain block of code Thread safe or in other words, it blocks all other Thread from entering the block which one thread is actually executing. The lock statement is actually producing Monitor.Enter in try and Monitor.Exit in finally. Hence it exclusively locks the block for you.

Limitation of Monitor

Now what is the limitation of lock statement? The first is that it locks the whole object and does not give you a chance to provide a Timeout seed. Hence it might produce deadlock situation in certain scenarios, but you can easily handle this using Monitor.TryEnter instead of Enter which lets you specify a timeout.

But the second and most important limitation of Monitor is that it always provide you an exclusive locking. Thus if a certain resource is read and written by multiple Threads at a time exclusive locking might produce inefficiencies. It is similar to what we see in Databases. Reads are generally cannot be inconsistent when multiple threads are reading it simultaneously only if some thread updates it. Hence exclusive locking is inefficient in case of reading a resource.

ReaderWriterLock allows shared locks together with exclusive locks. Hence it is possible to read the same resource using sharedlocking, each time the Readerlock is invoked the Lock count is increased but allows you to read the block of code inside it. ReaderWriterLock also give you an option for exclusive locking using WriteLock statement to eliminate inconsistent reads. Lets see how to use this with code.

static ReaderWriterLock locker = new ReaderWriterLock();
public static List Repository = new List();

public static long Sum()
{

    locker.AcquireReaderLock(1000);

    long counter = 0;
    try
    {
        for (int i = 0; i < Repository.Count; i++)
            Interlocked.Add(ref counter, Repository[i]);
    }
    finally
    {
        locker.ReleaseReaderLock();
    }
    return counter;
}

public static void AddToRepository(int nos)
{
    if (locker.IsWriterLockHeld)
        return;

    locker.AcquireWriterLock(1000);

    try
    {
        for (int i = 0; i < nos; i++)
            Repository.Add(i);
    }
    catch { }

    locker.ReleaseWriterLock();
}

The AddToRepository is only used to add some integer values to a List. You can easily lock the Repository using lock(Repository) statement, and that will mean an exclusive locking will be established. On the other hand, the code written inside AddToRepository also produces exclusive locking using AquireWriterLock statement. You can optionally specify the timeout value for the WriterLock. (specify TimeSman.Infinite when you don’t need timeout).
But on the method Sum which actually reads from the list an exclusive locking with create inefficiencies. We have used AquireReaderLock in this case to create Shared locking for the block. Hence concurrent reads can took place only when no WriterLock is established, but concurrent writer locks are not possible.

The ReaderWriterLock also have method to escalate from Reader to Writer and vice versa using UpgradeToWriterLock or DowngradeFromWriterLock

Every lock should always specify its Release statement in finally.

I hope this would come handy.

Thanks for reading.

6 thoughts on “Using ReaderWriterLock over Monitor for Thread Locking

  1. Pingback: Use of SpinLock for ThreadLocking - Daily .Net Tips

  2. Pingback: Cheatsheet: 2011 08.08 ~ 08.16 - gOODiDEA.NET

Comments are closed.