Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.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?

like image 453
derkyjadex Avatar asked Nov 23 '10 12:11

derkyjadex


3 Answers

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.

like image 124
CodesInChaos Avatar answered Dec 02 '22 19:12

CodesInChaos


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; 
} 
like image 23
Hinek Avatar answered Dec 02 '22 20:12

Hinek


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...

like image 37
Ian Ringrose Avatar answered Dec 02 '22 21:12

Ian Ringrose