Monday, April 23, 2012

Locks in C#

This is just something I didn’t know, so I thought I’d pass it along.

 When doing asynchronous coding in C#, it’s common to use the “lock” keyword, as in :

 lock(something)
 {
      // do stuff
}

One important thing that I didn’t know: the “lock” has no timeout. In some cases, this could be ok. But if the “something” that’s being done involves disk I/O or database access or anything that could potentially produce a lag, this could be bad. In some cases, it could even cause a deadlock.

Under the covers, “lock” just masks a call to Monitor.Enter and Monitor.Exit, so you can replace “lock” with these. Moreover, Monitor.TryEnter will allow you to set timouts, so you can use that. Even better, you can create a special object that implements IDisposable and do the “Monitor.Exit” in the Dispose() event. That way, any time the special object goes out of scope due to normal code flow or an exception, the Dispose() fires and you’re guaranteed to release the lock.

You can find a sample of this here:
http://www.koders.com/csharp/fid8EED099F752FABA10F6C8E661D1A6EF0736EB096.aspx

 Among other places. To use it, you just say:
 using (TimedLock.Lock(something, NumberOfMiliseconds))
 {
     // do stuff
}

So it works about the same way as “lock” only with the ability to pass a timeout. Very nice.

One other thing to remember is that locks are based on objects. If the “something” that you’re locking on is a simple type (say an int), .Net will box the int into a new object(). Unfortunately, the next thread that hits the lock sees that it’s an int and boxes it too, into it’s *own* object. The important thing is that thread1 and thread2 don’t share the object and both think they have a lock – which is really, really bad. So make sure the “something” is not a native type, but a real object. I sometimes use DateTime objects, since that also allows me to specify a datetime when the value would expire. But any subclass of object will do.


Till next time
--kevin

No comments:

Post a Comment