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;
}
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:
Thread.VolatileRead
(.NET Framework)Volatile.Read
(.NET 7)