Click here to Skip to main content
Click here to Skip to main content

ReaderWriterLock FTW!

, 27 Feb 2012
Rate this:
Please Sign up or sign in to vote.
Describes the .NET ReaderWriterLock object and how to use it effectively to create a thread safe Singleton.

[UPDATE: Please see the first comment below about some potential problems with the ReaderWriterLock class, and some solutions. -sj]

Recently I was encountering an issue on a SharePoint site where some site properties were getting cached in the HttpContext.Current.Cache. The logic went roughly like this:

  1. Read values from a SharePoint list
  2. Put the values into the cache
I'm oversimplifying, of course, but those are the important steps as they relate to this blog post. I had implemented proper locking, or so I thought, by using the C# lock statement. The pattern I learned long ago when dealing with creating a shared cache that multiple threads can access is to do something like this:
  1. Try accessing the object.
  2. If you get it, great! Go forth and use it.
  3. If you don't get it, try obtaining a lock (i.e. you're about to enter a critical section).
  4. Once you obtain the lock, try accessing the object again, just in case another thread beat you to it.
  5. If you get it, great! Release the lock, go forth and use it.
  6. If you still don't get it, create it, then put it in the cache.
  7. Exit the critical section.

This pattern prevents unnecessary locking if the object already exists in the cache. It also prevents the object from being created a second time.

As it turns out, the HttpContext.Current.Cache object isn't entirely thread-safe. Even though I was locking and such, I was unable to retrieve the site properties I was creating. To the second thread, it appeared that the properties were not in the cache, and the logic would get invoked to create it again.

That's when I did some research and discovered the System.Threading.ReaderWriterLock class. This gem allows multiple threads to access an object, but only allows one thread at a time to write to that object. The object has both a reader lock and a writer lock. Many reader locks are granted as long as there are no writer locks granted (or pending). If there is a writer lock that is being requested, it blocks until all the reader locks are released.

Another cool feature is that, once you have a reader lock, you can call "UpgradeToWriterLock" if you discover you need to write to the object. Once you're done, you then "DowngradeFromWriterLock" and then "ReleaseReaderLock". Or you can simply call "ReleaseLock", I believe, to release all locks obtained.

Best practice for using this object is to wrap it in a try…finally block of code. In the try part, acquire the lock and then do your stuff. In the finally part, release the lock. In this manner you ensure that you always release the locks you acquire, and the system never gets "out of balance".

Here's how I used it to solve my problem:

  1. Get a reader lock (will block only if another thread is writing)
  2. Try to get the properties
  3. If obtained, exit and use the properties (the finally kicks in to release the lock)
  4. If not obtained, upgrade to a writer lock (will block if any other reader or writer locks are being held).
  5. Try to get the properties again (nested try block)
  6. If obtained, exit and use the properties (the finally kicks in to downgrade the lock, and then the outer finally kicks in to release the reader lock)
  7. If not obtained, create it and return it (the finally blocks kick in as described in step 6)

It's more complex than using a simple lock statement, but I found that it was necessary in this case.

One final implementation note: the ReaderWriterLock object was stored in a "private static readonly" member variable so that it was accessible from any method that needed it, and so that all threads were accessing the same object.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

StevenLJackson1
Architect
United States United States
No Biography provided
Follow on   Twitter

Comments and Discussions

 
QuestionMany problems... PinmvpPaulo Zemek23-Feb-12 8:51 
AnswerRe: Many problems... PinmemberStevenLJackson127-Feb-12 7:20 
AnswerRe: Many problems... PinmemberStevenLJackson127-Feb-12 7:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 27 Feb 2012
Article Copyright 2012 by StevenLJackson1
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid