Can(should?) Lazy<T> be used as a caching technique?
Well, it's not thread-safe in that one thread could still see the old value after another thread sees the new value after invalidation - because the first thread could have not seen the change to cachedAttribute
. In theory, that situation could perpetuate forever, although it's pretty unlikely :)
Using Lazy<T>
as a cache of unchanging values seems like a better idea to me - more in line with how it was intended - but if you can cope with the possibility of using an old "invalidated" value for an arbitrarily long period in another thread, I think this would be okay.
cachedAttribute
is a shared resource that needs to be protected from concurrent modification.
Protect it with a lock
:
private readonly object gate = new object();public string CachedAttr{ get { Lazy<string> lazy; lock (gate) // 1. Lock { lazy = this.cachedAttribute; // 2. Get current Lazy<string> } // 3. Unlock return lazy.Value // 4. Get value of Lazy<string> // outside lock }}void InvalidateCache(){ lock (gate) // 1. Lock { // 2. Assign new Lazy<string> cachedAttribute = new Lazy<string>(initCache, true); } // 3. Unlock}
or use Interlocked.Exchange:
void InvalidateCache(){ Interlocked.Exchange(ref cachedAttribute, new Lazy<string>(initCache, true));}
volatile
might work as well in this scenario, but it makes my head hurt.