Posts
8
Comments
27
Trackbacks
0
August 2008 Entries
ReaderWriterLock(Slim) Extension Methods

With the .NET framework 3.5 came a new implementation of the reader writer lock that solved many flaws of the original design. Joe Duffy describes in detail what's new in ReaderWriterLockSlim, how it differs from the old version and why a new class was needed to do the same thing.

In most of my applications, when I use a reader writer lock I use them a lot.  Fortunately, using the lock is straight forward:

var rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
rwLock.EnterReadLock();

try {
// do stuff
} catch (Exception ex) {
// handle exception
} finally {
// release the lock
rwLock.ExitReadLock();
}

 

But when you're acquiring/releasing locks a lot, your code is littered with try-catch-finally's.

This isn't an earth-shattering-world-heating-climate-cooling-mass-destruction problem, but I'm a big fan of simplifying and cleaning up code where ever I can - for no other reason than the KISS principle.

In C# 3.0, extension methods and lambda's provide us with a great way to extend and wrap existing class behaviour. I used lambdas in continuations in my ActionDisposable post to give a collection class some public locking.

With extension methods, I can extend the ReaderWriterLockSlim class itself to simplify the use of the lock.

using System;

namespace System.Threading {

public static class ReaderWriteLockExtensions {
#region Disposable

struct Disposable : IDisposable {
readonly Action action;

public Disposable(Action action) {
this.action = action;
}

public void Dispose() {
action();
}

}

#endregion

#region Lock Helpers

public static IDisposable ReadLock(this ReaderWriterLockSlim l) {
l.EnterReadLock();
return new Disposable(l.ExitReadLock);
}

public static IDisposable UpgradableReadLock(this ReaderWriterLockSlim l) {
l.EnterUpgradeableReadLock();
return new Disposable(l.ExitUpgradeableReadLock);
}

public static IDisposable WriteLock(this ReaderWriterLockSlim l) {
l.EnterWriteLock();
return new Disposable(l.ExitWriteLock);
}

#endregion
}
}

 

ReadLock(), UpgradableReadLock() and WriteLock() return IDisposable, which can be used in using() blocks that automatically clean-up even when exceptions are thrown.

var rwLock = new ReaderWriterLockSlim();
using (rwLock.ReadLock()) {
// do reading stuff

}

It's a little easier to read, and has certainly cleaned up our heavily locked code.

posted @ Friday, August 08, 2008 4:28 PM | Feedback (5)