Multithreading: the volatile keyword – part II

In the last post, I’ve showed you some code I’ve written in  the past and asked if there was anything wrong with it. Here’s the code again:

class Lazy {
  private SomeObject _object;
  private Object _locker = new Object();
  public SomeObject SomeObject {
    get {
      if (_object == null) {
        lock (_locker) {
          if (_object == null) {
            _object = new SomeObject();
          }
        }
      }
      return _object;
    }
  }
}

Here’s main idea (for the double-checked locked pattern): you start by checking the instance against null. If it is null, then you acquire the lock and test again. We’re testing it again because someone might have already initialized the instance in the time that passed since the initial test and the lock acquisition. Ok, so is there anything wrong with this?

To answer this question correctly, we need to go back to the memory model supported by the CLR. As we’ve seen, the CLR won’t allow store-store reorderings (meaning that all the other types are allowed). If we assume that SomeObject has fields (and this is really a valid assumption), then they will be initialized during construction. So, if we’re using the CLR, everything should be ok because store-store aren’t allowed.

However, the CLR allows load-load reorderings, meaning that the load of the instance can be moved after the load of its fields, meaning that we could get into trouble. And what happens if we’re writing code that should be run against another ECMA CLI implementation? For instance,say we want to write code that will also run in Mono (I don’t really know Mono,so I don’t know if it follows the CLR 2.0 tighter rules). In this case, store-store reordering are possible and our code might break if the store of the _object instance occurs before the store of its fields. In this case, the testing condition will be null (_object won’t be null) but its fields are because they haven’t been written to yet. Solving this is as simple as adding volatile (recall that volatile allows only store-load reordering!). Here’s the code again:

class Lazy {
  private volatile SomeObject _object;
  private Object _locker = new Object();
  public SomeObject SomeObject {
    get {
      if (_object == null) {
        lock (_locker) {
          if (_object == null) {
            _object = new SomeObject();
          }
        }
      }
      return _object;
    }
  }
}

And that’s it. Adding the volatile keyword solves all the problems mentioned before. Keep tuned for more on multithreading.

Advertisements

~ by Luis Abreu on July 6, 2009.

2 Responses to “Multithreading: the volatile keyword – part II”

  1. I thought Monitor.Enter and Monitor.Exit provided memory fences implicitly. Is that not the case?

  2. Yes, they do, but don”t forget that load-load are allowed here (ex.: fields of the object loaded before the instance) and some processors do use it. Applying the volatile word to that instance doesn”t let that happen. You don”t need to apply it to the instance type fields though. Joe Duffy has a nice post on it here http://www.bluebytesoftware.com/blog/PermaLink,guid,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s

 
%d bloggers like this: