'.NET thread-safe cached result

I have something like the following in C#:

private double _x;
private bool _xCalculated;

private double GetX() {
    if (!_xCalculated) {
        _x = ... // some relatively expensive calculation
        _xCalculated = true;
    }

    return _x;
}

My question is, is this thread-safe? As far as I can tell, the worst outcome of this is that two or more threads enter this method at the same time and calculate _x multiple times, but the result is guaranteed to be the same for any instance of this class, so that's not a particularly huge problem.

Is my understanding of this correct?



Solution 1:[1]

A few observations:

  1. The store into the double might not be atomic
  2. The write to the bool should be atomic
  3. Depending on the CPU architecture memory operations might be reordered
  4. If no reordering occurs the code should work

While I think the x86 memory ordering guarantees make this safe I'm not entirely sure about that. The memory ordering guarantees of .net have been strengthened recently(I think in .net 4) to match the guarantees of x86.

Memory Model in .net
More on memory ordering
This states that stores are not reordered in .net which I think means that your code is safe. But lockless programming is hard, so I might be overlooking some subtle issues. Perhaps the read in the if clause can cause problems.

I recommend not using this code unless you're a threading expert and really really need the performance. Else just use something more explicit like locks. Locks are not that expensive if they're not contended.

Solution 2:[2]

It is not thread-safe. And yes, your understanding is correct. You could use the lock() statement to make it thread-safe.

http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx

private object objLock = new object();
private double GetX() {
    lock(objLock) {
        if (!_xCalculated) { 
            _x = ... // some relatively expensive calculation 
            _xCalculated = true; 
        } 
    }
    return _x; 
} 

Solution 3:[3]

It depends on the platform, I don't think this is safe with the .NET memory model as per its spec, but I think it is OK on the current Microsoft CLR. The issue is the extent a CPU is allowed to reorder memory writes.

Can someone please come up with the detailed links to the spec...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Glorfindel
Solution 2
Solution 3 Lars Truijens