Friday, January 18, 2008 10:14 AM Brian Rudolph

Thread Safe Dictionary in .NET with ReaderWriterLockSlim

 

Since MS has decided to not include a thread-safe dictionary in the .NET framework, many of us have been forced to implement our own.  What MS has done now with .NET 3.5 is given us a newer locking mechanism which makes this task easier. 

Previously, we had 2 lock mechanisms, neither of which worked very well for my uses.  The first is the Lock statement.  While this method is effective, it causes serious contention issues with simultaneous reads\writes.  Since it is generally safe to execute multiple concurrent reads from a dictionary, this was a huge performance flaw as the Lock statement was forcing us to perform all actions against the object in a serial fashion.

So that left ReaderWriterLock, which would allow us to take out Reader & Writer locks independently.  This seemed to be the answer.  Unfortunately, after further testing and review, MS and the dev communities warned against this lock type as it could have unintended consequences in certain situations.  The explanations for these I will not go in to, a simple Google search will answer those questions.  For the most part, I don't have the mental capacity to understand, much less explain the failures.  I will tell you that I have tested this method, and ran in to some issues, and subsequently abandoned the approach.

With .NET 3.5 comes the brand-spankin-new ReaderWriterLockSlim.  ReaderWriterLockSlim is similar to the ReaderWriterLock in functionality, minus some of the drawbacks.  Of course any new approach will bring on its own consequences, and if you do a little research, you will find that Slim isn't infallible either. 

Many of our applications implement the Factory model.  Factory models are great, they are extensible, and they can be extremely performant.  With that said, any data driven application that uses the Factory model without a caching model, will most likely perform poorly.  So, in our factories, we build in a caching mechanism.  A very simple type and ID based cache that allows us to persist commonly used objects to in-memory cache for a specific amount of time.  I won't go in to the implementation of this model here as every caching implementation has its own needs and wants.

At the heart of this and likely any caching model is inevitably a Dictionary or Dictionary like structure.  MS programmers have spent countless hours fine-tuning the Dictionary class to make it as performant as possible.  I challenge anyone to write a managed Dictionary that performs as well in such a wide variety of scenarios.  I've tried and failed.  Unfortunately, MS has not provided a thread-safe implementation.  Generally when you run into the question of thread-safety, most people have no idea what you are talking about.  The problem with writing truly thread-safe code that can work in any scenario is that you will sacrifice performance.  If you tailor your thread-safe mechanisms to your particular problem, you can generally maintain a higher level of performance.

The reason we need thread-safety is not that we are specifically spawning threads.  In IIS, worker processes are inherently multi-threaded.  Therefore, using static objects in a web-farm generally requires some level of thread safety, otherwise you will get dreaded "An item with the same key has already been added" errors.  This is because between the time you check to see if a key already exists in your dictionary and the time you insert it, some other thread may have inserted this key.  This is especially the case in object factories, because you have multiple threads attempting to access/create objects and subsequently cache them.

This is the code I've written.  This has not been tested yet, so please use it carefully.  I will keep this post updated with any changes and test results.  I also have not made this class utilize lock escalation, which ReaderWriterLockSlim supports.  As always, please perform your own testing.

ThreadSafeDictionary.zip

 

Filed under: , ,

Comments

# re: Thread Safe Dictionary in .NET with ReaderWriterLockSlim

Friday, February 01, 2008 9:03 AM by Joris

Hi Brian.

This article closely describes the problem we are having, implementing a thread safe Hastable. As we are creating a framework where performance is one of the key requirements, providing thread safety is no picnic. Have you done any additional testing/research concerning this topic? It also seems that the link to you thread safe dictionary is broken. Could you please fix it, so I can take a look at your implementation?

Thanks a lot!

# re: Thread Safe Dictionary in .NET with ReaderWriterLockSlim

Saturday, February 02, 2008 10:14 AM by Brian Rudolph

The link has been updated.  If you have any more questions let me know.

# Thread-safe caching mechanism using a Hashtable

Friday, February 15, 2008 7:12 AM by Joris Dresselaers

Hi. I wanted to start my first blog post with some interesting material ;-) On our current project we

# re: Thread Safe Dictionary in .NET with ReaderWriterLockSlim

Monday, March 17, 2008 4:28 PM by Mike

One minor thing, and one potentially major thing...

First the minor; you're using the recursive locking policy but you I didn't see any methods that can actually recursively lock.  Switching to non-recurse policy will give you a slightly more efficient lock.

The bigger problem is the key enumerator.  The Dictionary key enumerator is not a static copy - according to the docs - it refers back to the actual keys.  So changes in the dictionary show up in changes to the enumerator.   If it can pick up the changes then it's breaking your synchronization.  

Leave a Comment

(required) 
(required) 
(optional)
(required)