No, because inited not volatile . volatile gives you free memory and acquires the fences you need to establish the right relationship between them.
If before inited is set to true, if inited not set, then the value may not be completely written when another thread reads inited and sees it as true, which may lead to a semi-constructed object being returned. Similarly, if there is a fence in the first test, but there is no corresponding fence, before reading inited , it is possible that the object is completely constructed, but that the CPU core, which saw inited as true, has not yet seen the memory effects of writing value (cache consistency is not necessary means that the effects of sequential recordings are visible in order on other cores). This again could potentially result in a constructed object.
This, incidentally, is an instance of the already very well-documented double-check lock pattern.
Instead of using a lambda that captures local variables (which will cause the compiler to generate an implicit class to store private variables in non-volatile fields), I suggest explicitly creating your own class with volatile , filed for value .
private class Memoized<T> { public T value; public volatile bool inited; } private static Func<T> Memoize<T>(Func<T> func) { var memoized = new Memoized<T>(); return () => { if (memoized.inited) return memoized.value; lock (memoized) { if (!memoized.inited) { memoized.value = func(); memoized.inited = true; } } return memoized.value; }; }
Of course, as others have said, Lazy<T> exists for this very purpose. Use it instead of riding yourself, but itβs always useful to know the theory of how something works.
source share