Search code examples
c#multithreading.net-4.0volatilelock-free

Generic Volatile.Read to Thread.VolatileRead conversion


I need to get this code from .NET 4.5+ working on .NET 4.0. The generic Volatile.Read isn't available in that version. I'm trying to use the Thread.VolatileRead to get this working. I need to know if this outright a bad idea and if not, what I should test for?

See what I replaced in the commented line.

internal static TValue EnsureSingletonInitialized<TValue, TArg>(ref TValue value,
    TArg arg, Func<TArg, TValue> initialize)
    where TValue : class
{
    //TValue currentValue = Volatile.Read(ref value);

    object o = value;
    TValue currentValue = (TValue)Thread.VolatileRead(ref o);

    if (null != currentValue)
        return currentValue;

    TValue candidateValue = initialize(arg);

    return Interlocked.CompareExchange(ref value, candidateValue, null) ?? candidateValue;
}

Solution

  • The safest implementations of the missing Read<T>/Write<T> methods are probably these:

    public static class VolatileEx
    {
        public static T Read<T>(ref T location) where T : class
        {
            return Interlocked.CompareExchange(ref location, null, null);
        }
    
        public static void Write<T>(ref T location, T value) where T : class
        {
            Interlocked.Exchange(ref location, value);
        }
    }
    

    Using the Interlocked ensures that the Read/Write are atomic, and also that the preceding/following instructions will not be reordered. The Interlocked APIs impose full memory barriers, so they are more expensive than the Volatile APIs that impose half fences. But since you downgraded to an older .NET platform, losing some performance is to be expected.

    Source code: