API's that Suck

October 24, 2009

Making Reader/Writer Locks More Palatable

Filed under: Uncategorized — Grauenwolf @ 10:16 pm

The lock most .NET developers are most familiar is the Monitor. Used via the handy lock/SyncLock construct, it is suitable for most low-contention applications. But when many threads are all trying to access a protected resource at the same time, something a bit more sophisticated is in order. If the number of readers vastly outnumber the number of writers, a reader/writer lock is in order. Here is how Microsoft recommends using it:

try
{
    theLock.EnterReadLock();
    //code
}
finally
{
    theLock.ExitReadLock();
}

This is quite tedious compared the lock/SyncLock construct.

lock (theLock)
{
    //code
}

So how we fix this? It would be nice if Microsoft were to extend the language somehow to allow for a nice syntax in a variety of locks. But since that is probably not going to happen, let us look at the original example again. Looks familiar, doesn’t it? Somewhat like the usage pattern of IDisposable objects.

try
{
    obj = new Resource();
    //code
}
finally
{
    if (obj != null) obj.Dispose();
}

Aside from a few poor souls stuck using VB 7, no one actually writes code like that.  Instead we use the Using construct.

using (obj = new Resource())
{
    //code
}

So now we have our construct, but how do we actually use it? By creating a shim that can be disposed. First, let us look at how we want to call it:

using (theLock.ReadSection())
{
    //code
}

That is about as easy as it is going to get in C#/VB . As for the shim, it is a private class that links back to the real Reader/Writer Lock. Developers should never really know they are using this object, from their perspective they just happened to call ReadSection inside a using construct’s header.

    <Extension()> Public Function ReadSection(ByVal lock As Global.System.Threading.ReaderWriterLockSlim) As IDisposable
        Return New LockToken(lock, LockMode.Read)
    End Function

    <Extension()> Public Function UpgradeableReadSection(ByVal lock As Global.System.Threading.ReaderWriterLockSlim) As IDisposable
        Return New LockToken(lock, LockMode.Upgradable)
    End Function

    <Extension()> Public Function WriteSection(ByVal lock As Global.System.Threading.ReaderWriterLockSlim) As IDisposable
        Return New LockToken(lock, LockMode.Write)
    End Function

    Private NotInheritable Class LockToken
        Implements IDisposable
        Private m_Mode As LockMode
        Private m_Lock As ReaderWriterLockSlim
        Private m_Disposed As Boolean = False

        Friend Sub New(ByVal lock As ReaderWriterLockSlim, ByVal mode As LockMode)
            m_Lock = lock
            m_Mode = mode
            Select Case mode
                Case LockMode.Read
                    m_Lock.EnterReadLock()
                Case LockMode.Upgradable
                    m_Lock.EnterUpgradeableReadLock()
                Case LockMode.Write
                    m_Lock.EnterWriteLock()
            End Select
        End Sub

        Private Sub Dispose(ByVal disposing As Boolean)
            If Not Me.m_Disposed Then
                If disposing Then
                    Select Case m_Mode
                        Case LockMode.Read
                            m_Lock.ExitReadLock()
                        Case LockMode.Upgradable
                            m_Lock.ExitUpgradeableReadLock()
                        Case LockMode.Write
                            m_Lock.ExitWriteLock()
                    End Select
                End If
                m_Lock = Nothing
            End If
            Me.m_Disposed = True
        End Sub

        Private Sub Dispose() Implements IDisposable.Dispose
            Dispose(True)
        End Sub

    End Class

    Private Enum LockMode
        Read
        Upgradable
        Write
    End Enum

End Module

The code for this is in version 2.2 of ClrExtensions.

Advertisements

1 Comment »

  1. Very nice – thanks

    Comment by Paul — August 4, 2010 @ 12:47 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: