Multithreading: the volatile keyword – part II

Published Mon, Jul 6 2009 9:53

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.

Filed under: ,

Comments

# Timothy Fries said on Monday, July 06, 2009 12:47 PM

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

# Luis Abreu said on Monday, July 06, 2009 1:23 PM

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 www.bluebytesoftware.com/.../PermaLink,guid,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx

# LA.NET [EN] said on Monday, July 06, 2009 3:25 PM

In the previous post we’ve seen how we can use the C# volatile keyword to guarantee that those nasty

# ASPInsiders said on Monday, July 06, 2009 4:20 PM

In the previous post we’ve seen how we can use the C# volatile keyword to guarantee that those nasty

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above:  

Search

This Blog

Tags

Community

Archives

Syndication

Email Notifications

News




  • View Luis Abreu's profile on LinkedIn


    Follow me at Twitter

    My books

    Silverlight 4.0: Curso Completo

    ASP.NET 4.0: Curso Completo

    Portuguese LINQ book cover

    Portuguese ASP.NET 3.5 book cover

    Portuguese ASP.NET AJAX book cover

    Portuguese ASP.NET AJAX book cover