Can (should?) Lazy <T> be used as a cache method?

I would like to use the .NET Lazy<T> class to implement secure thread caching. Suppose we had the following setup:

 class Foo { Lazy<string> cachedAttribute; Foo() { invalidateCache(); } string initCache() { string returnVal = ""; //CALCULATE RETURNVAL HERE return returnVal; } public String CachedAttr { get { return cachedAttribute.Value; } } void invalidateCache() { cachedAttribute = new Lazy<string>(initCache, true); } } 

My questions:

  • Will it even work?
  • How should a lock work?

I feel like I don’t have a lock somewhere near invalidateCache, but for life I can’t understand what it is.

I am sure that there is a problem somewhere, I just did not understand where.

[EDIT]

Well, it looks like I was right, there were things that I did not think about. If the stream sees an obsolete cache, it will be very bad, so it looks "Lazy" is not safe enough. There is a lot of property available, though, so I was involved in pre-mature optimization in the hope that I could learn something and have a sample that would be used in the future for streaming caching. I will continue to work on this.

PS: I decided to make the object unsafe and gain access to the object, which will be carefully monitored.

+6
multithreading c # caching locking lazy-loading
source share
2 answers

Well, it is not thread safe in that one thread can still see the old value after another thread sees the new value after the invalidation - because the first thread could not see the change to cachedAttribute . Theoretically, this situation can perpetuate forever, although this is quite unlikely :)

Using Lazy<T> as a cache of constant values ​​seems to me a better idea - more in accordance with how it was intended - but if you can cope with the possibility of using the old "invalid" value for an arbitrarily long period in another topic, I think that everything will be fine.

+8
source share

cachedAttribute is a shared resource that must be protected from simultaneous modification.

Protect it with 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 may work in this scenario too, but my head hurts.

+3
source share

All Articles