.NET 4.0's System.Lazy<T> class offers three Thread-Safety modes via the enum LazyThreadSafetyMode, which I'll summarise as:
- LazyThreadSafetyMode.None - Not thread safe.
- LazyThreadSafetyMode.ExecutionAndPublication - Only one concurrent thread will attempt to create the underlying value. On successful creation, all waiting threads will receive the same value. If an unhandled exception occurs during creation, it will be re-thrown on each waiting thread, cached and re-thrown on each subsequent attempt to access the underlying value.
- LazyThreadSafetyMode.PublicationOnly - Multiple concurrent threads will attempt to create the underlying value but the first to succeed will determine the value passed to all threads. If an unhandled exception occurs during creation, it will not be cached and concurrent & subsequent attempts to access the underlying value will re-try the creation & may succeed.
I'd like to have a lazy-initialized value which follows slightly different thread-safety rules, namely:
Only one concurrent thread will attempt to create the underlying value. On successful creation, all waiting threads will receive the same value. If an unhandled exception occurs during creation, it will be re-thrown on each waiting thread, but it will not be cached and subsequent attempts to access the underlying value will re-try the creation & may succeed.
So the key differince with LazyThreadSafetyMode.ExecutionAndPublication is that if a "first go" at creation fails, it can be re-attempted at a later time.
Is there an existing (.NET 4.0) class that offers these semantics, or will I have to roll my own? If I roll my own is there a smart way to re-use the existing Lazy<T> within the implementation to avoid explicit locking/synchronization?
N.B. For a use case, imagine that "creation" is potentially expensive and prone to intermittent error, involving e.g. getting a large chunk of data from a remote server. I wouldn't want to make multiple concurrent attempts to get the data since they'll likely all fail or all succeed. However, if they fail, I'd like to be able to retry later on.
LazyWithSprinkles<T>
? It sounds like there's a problem that's slightly bigger than what you've posted, which suggests a much different solution than something that looks similar toLazy<T>
. – LacombeLazy<Task<T>>
that, upon the first request, spins up aTask<T>
that makes the request repeatedly until it finally succeeds (or throws an error that it doesn't know how to recover from); callers could then wait on thatTask<T>
for as long as they can justify. It's not exactly the same as what you're looking for, though, because sometimes you'll timeout 100ms before the value would have been ready... but is that actually different from having to retry later if an exception is thrown in yourLazy<T>
-like idea? – LacombeLazyWithKnobsOn<T>
) – Medwin