An Alternative Approach To Monitors

Credit where credit is due - some of the ideas here are also embodied in Jeffrey Richter's Safe Thread Synchronization article, and others are in Ian Griffiths' blog entry on locking with timeouts. The C# team have also said that were they designing C# again now, they wouldn't have included the lock keyword, instead making sure that a mechanism for using the using statement for the same job would be available. (My main problem with the lock keyword is that it's the name I would almost always naturally use for the variable containing the monitor in a single-lock class.)

Both Java and .NET made the same mistake when it came to locking, I believe. At first it seems like having a monitor for every object is a good idea, but in practice if you care about monitor privacy, you need to have an extra field in classes which need to worry about thread safety anyway. This is basically the point Jeffrey Richter makes in the article referenced above, and the same thought had been going through my head before I saw his elegant explanation of it.

I then also heard about Ian Griffiths' quest for attempts to acquire monitors with a timeout, in a way which didn't make code really hard to follow. Using Monitor.TryEnter will work, but then you've got to put the finally block in yourself, and test the return value from the method. Ian reasoned that usually what you really want is just an exception if you can't acquire a lock within a reasonable time limit - it indicates that you've got deadlock, basically.

What intrigued me more than the idea was the implementation - specifically, using the using statement to neatly acquire the lock and release it at the end of a block. This page (and the referenced code) attempts to combine the two ideas, to give an alternative to normal locking which is clearer in intention than using a plain object, which still maintains the neatness of code, and which allows locking with timeouts.

Over time, I've expanded the initial concept to allow deadlock detection in terms of locks having an order imposed on them, and made a few other tweaks. The code is available as part of my Miscellaneous Utility library, and the usage page has more details of exactly what's available. This page now just covers the basic principles.

Essentially, the three primary types involved are:

SyncLock
This is the main class callers will use. It basically encapsulates a monitor and a name for it. (If you can think of a nicer name than this which doesn't clash obviously with the framework, please mail me.)
LockTimeoutException
Obvious - thrown when an attempt to lock a monitor fails due to timeout. (I would have used just TimeoutException, but that seems to be specific to Windows Services, annoyingly enough - to my mind, it should have been in the System namespace.)
LockToken
This is a struct returned by SyncLock when the monitor has been successfully locked - it must be disposed in order to release the monitor. The reason for making this a struct rather than a class is that it then only takes up a bit of stack space for each lock operation, rather than needing to create a whole extra object each time, which would be nasty for performance.

The typical usage is very straightforward:

// Create the lock - almost always as a field
// This constructor overload creates a named
// lock with a 20 second default timeout. Either the
// name or the default timeout can be omitted.
SyncLock syncLock = new SyncLock ("Some name");

// Lock it using its default timeout
using (syncLock.Lock())
{
                  // Do stuff here
}

// ... or lock it with a specific timeout
using (syncLock.Lock(10000))
{
}

Please mail me with any comments or criticisms.


Next page: When to use Threads
Previous page: Choosing What To Lock On

Back to the main C# page.