Search code examples
c#volatile

Given doubles can't be used in volatile fields, is this a safe alternative?


Given doubles can't be used in volatile fields, is this a safe alternative? Or could it lead to a null pointer exception.

public sealed class DoubleStorage
{
    public readonly double Value;

    public DoubleStorage(double value)
    {
        this.Value = value;
    }

    public static readonly DoubleStorage Zero = new DoubleStorage(0);
}

public sealed class Val
{
    private volatile DoubleStorage boostResult = DoubleStorage.Zero;

    public double ThreadSafeDouble
    {
        set
        {
            //is this assignment attomic?
            boostResult = new DoubleStorage(value);
        }
        get
        {
            //or could this give null pointer exception?
            return boostResult.Value;
        }
    }
}

Solution

  • Yes, accessing references is atomic.

    However, you can just box the double, you don't have to create a class to encapsulate it:

    public sealed class Val {
    
      private volatile object boostResult = 0.0;
    
      public double ThreadSafeDouble {
        set {
            boostResult = value;
        }
        get {
            return (double)boostResult;
        }
      }
    }
    

    Assigning a double to the variable will create an object that boxes the double, then assigns the reference to the variable. As the reference assignment is atomic, it's thread safe.

    When unboxing the double, reading the reference from the variable is atomic, so it's thread safe eventhough reading the double isn't atomic. As the boxed double is immutable, a specific boxed value will never change.


    Or what about a generic version:

    public sealed class ThreadSafe<T> where T : struct {
    
      private volatile object _value;
    
      public ThreadSafe() {
        Value = default(T);
      }
    
      public ThreadSafe(T value) {
        Value = value;
      }
    
      public T Value {
        get {
          return (T)_value;
        }
        set {
          _value = value;
        }
      }
    
    }