LA.NET [EN]

Jul 06

[Update: Brad detected a flaw in the code: I had forgotten to initialize the _initialized field. Thanks!]

[Update2: Brad detected another flaw in the code: return _instance must be outside the if. Thanks!]

In the previous post we’ve seen how we can use the C# volatile keyword to guarantee that those nasty load-load reordering stay away from our code. As I’ve said before, we can also use the static Thread.VolatileRead or Thread.VolatileWrite for having more control over the way fences are applied to our code. Going back to our previous volatile example, the question is: do we really need a fence whenever we access our instance variable?

Looking at the code, I guess that we can get  away by just using an acquire fence on the initialization of the instance. Recall that an acquire fence is an optimization of the full fence and ensures that no load or store that comes after the fence can be moved before the fence (it’s just what we need to ensure proper initialization and eliminate the possible load/load reorderings allowed by the CLR).

With this in mind, lets update our sample, ok? Btw, we’ll be using another variable for controlling initialization (we’re picking an integer). This is your best option for initializing value types since you can’t control it size or check it for null (don’t forget our previous discussion on word size, alignment and .NET). Here’s the final code:

class Lazy{
  private Object _locker = new Object();
  private SomeObject _instance = null;
  private Int32 _initialized = 0;
  public SomeObject SomeObject {
    get {
      if (Thread.VolatileRead(ref _initialized) == 0) {
        lock (_locker) {
          if (_initialized == 0) {
            _instance = new SomeObject();
_initialized = 1; } }
}
return _instance; } } }

This code is also correct and will behave properly in all the current architectures that run Windows and the CLR. There’s no need for running another VolatileRead on the inner comparison due to a thing called control dependency (check this post by Joe Duffy for more info). Notice that in these posts our main objective is ensuring that you end up getting only one instance of a specific type. As I’ve said, if you don’t care about creating multiple instances and only need to ensure that you’ll have only one active instance, you can only use the Interlocked.CompareExchange method for that. We’ll see how in the next post. Keep tuned!

11 comments so far

  1. Brad
    12:25 am - 7-7-2009

    These articles are fantastic! I only discovered this site yesterday, so I have a lot of catching up and backreading to do.

    Thank you very much!

  2. Brad
    12:59 am - 7-7-2009

    One quick question, where does the value of _initialized change from 0?

  3. Brad
    4:22 am - 7-13-2009

    Another flaw, the return _instance; needs to go one bracket down :) (it currently returns in the if statement)

  4. Brad
    11:24 am - 7-17-2009

    I keep revisiting this code, as im using it throughout my applications now. I have a question, would you want to put a volatilewrite for setting initialize?

  5. luisabreu
    12:53 pm - 7-17-2009

    I”d say no. Check Joe Duffy”s excellent post I mentioned above. I think that it might help you understand why…

  6. J
    3:16 pm - 7-17-2009

    Duffy”s blog link is broken.

  7. luisabreu
    3:45 pm - 7-17-2009
  8. Brad
    9:12 am - 8-13-2009

    Sorry to bring up an old post, but they also need to be made static :)

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>