Multithreading: reader/writer locks

In the previous posts, we’ve seen how we can use monitors and any CLR object for getting a critical region. Whenever you need to get a critical region, using a CLR lock for ensuring proper access. However, there will be times when, for instance, you’ll have much more reads than writes. In these cases, using a lock is still correct, but it is not the best way to get good performance.

This is where the reader/writer locks enter. When using these type of locks, a thread will have to specify the type of access it desires (read or write). At any time, there can only be a write lock. However, there can be several read locks (as long as there are no write locks).

In practice, this means that we can have several threads in the region if those threads are only interested in “reading”. Whenever a thread says that it’s interested in writing,it needs to acquire the write lock (or upgrade the read lock,if it has one). When the write lock is acquired, all the other readers (and writers) need to wait until that thread leaves the critical region and releases the lock.

In .NET, there are two types of reader/writer locks: the old ReaderWriterLock and the new (as of .NET 3.5) ReaderWriterLockSlim. I’ll only be looking at the ReaderWriterLockSlim class because I’m currently working over 3.5 only.

When we instantiate a RederWriterLockSlim, we can decide if recursion will be allowed. By default, it won’t, so if you need it, you’ll have to use the constructor which expects a value from the LockRecursionPolicy enumeration. After getting a valid reference to a lock of this type, we can use one of several methods for acquiring a read or write lock. In fact, the lock supports a third type of lock: an upgrade lock. The first two are the ones most people are used to; the last can be used when a thread isn’t sure if it will need read or write access.

This last scenario involves calling the EnterUpgradeableReadLock. After getting the updatable lock, the thread must decide (in the least amount of time!) if it needs read or write access. If it needs read access, it should call the EnterReadLock method; on the other hand, if it needs write access, it should simply call the EnterWriteLock method. When you decide to go with the read lock, you should also call the ExitUpgradeableReadLock method (right after the EnterReadLock method call) so that other previously read and upgrade locks calls that were waiting can proceed.

Ok, now we’re ready to see some code:

class MyCache: IDisposable {
    private IDictionary<String, Object> _cache = 
                                                                  new Dictionary<String, Object>();
    private ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
    public Object this[String key]{
        get {
            try {
                return _cache[key];
            } finally {
        set {
            try {
                _cache[key] = value;
            } finally {
    public void Dispose() {
    ~MyCache() {
    private void Dispose(Boolean disposing) {
        if (!disposing) {

This is really simple class which uses a reader lock for getting a value from the list and a writer lock for writing an entry to this custom cache (notice that we’re not using upgradeable locks in this simple example). As you can see, we’re implementing IDisposable to ensure that we release the reader/writer lock when we’re done. Here’s some code that tests the previous “cache” and that starts several writers and readers:

static IEnumerable<Thread> CreateWriterThreads(String[] keys, MyCache cache){
    var aux = Enumerable.Range(1, keys.Length)
                        .Select( i => new Thread( () => {
                            var key = "item" + i.ToString();                                    
                            cache[key] = DateTime.Now; }) ) ;
    return aux;
static IEnumerable<Thread> CreateReaderThreads( Int32 numberReaders, String[] keys, MyCache cache){
    var aux = Enumerable.Range(1, numberReaders)
        .Select(i => new Thread(() => {
            Console.WriteLine("Thread {0} starting", i);
            foreach (var key in keys) {
                try {
                    Console.WriteLine("item {0} in thread {1} with value {2}",

                       key, i, cache[key]);
                } catch {
                    Console.WriteLine("item {0} in thread {1} not in cache yet", key, i);
            Console.WriteLine("Thread {0} ending", i);
        return aux;
static void Main(string[] args) {
    using (var cache = new MyCache()) {
        var keys = new[] { "item1", "item2", "item3" };
        var writerThreads = CreateWriterThreads(keys, cache);
        var readerThreads = CreateReaderThreads(10, keys, cache);
        foreach (var writer in writerThreads) {
        foreach (var reader in readerThreads) {

        Thread.Sleep(10000); //wait enough time for everything to complete

And that’s all for today. Keep tuned for more on multithreading.


~ by Luis Abreu on May 26, 2009.

2 Responses to “Multithreading: reader/writer locks”

  1. ?? ??????? ?? ????????, ????????? ????????????????
    ???? ????? ???????
    ????? ?? ???????????? ???????, ???? ? ??????? ????????? ??????? ???? ? ????????? ????, ??? ??? ????

  2. hello

    Just tought id share a site i found a while ago,
    I have been using this advice for 2 months and have all ready made
    $280 with just the tips and help,

    It is probably more for the Noob”s like me, but I found it very helpful, and you might to

    hope you all find it as helpful as I did, let me know how you get on


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: