Skip to content

Instantly share code, notes, and snippets.

@ArtemAvramenko
Last active October 5, 2023 11:53
Show Gist options
  • Save ArtemAvramenko/1c9d4d90a05dcbbe24d0c64848f48a50 to your computer and use it in GitHub Desktop.
Save ArtemAvramenko/1c9d4d90a05dcbbe24d0c64848f48a50 to your computer and use it in GitHub Desktop.
Lazy pattern implementation with asynchronous locks that release the thread for waiting time
// https://stackoverflow.com/questions/17975609/lazy-load-properties-with-async/41141728#41141728
#nullable enable
public class AsyncLazy<T>
{
private Func<Task<T>>? _valueFactory;
private volatile SemaphoreSlim? _semaphore = new(1, 1);
private volatile Boxed? _boxed;
public AsyncLazy(Func<Task<T>> valueFactory)
{
_valueFactory = valueFactory ?? throw new ArgumentNullException(nameof(valueFactory));
}
public Task<T> Value => GetValue();
public bool IsValueCreated => _boxed != null && _boxed.Exception == null;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private async Task<T> GetValue()
{
var result = _boxed;
if (result == null)
{
var semaphore = _semaphore;
if (semaphore != null)
{
await semaphore.WaitAsync();
try
{
if (_boxed == null)
{
try
{
var value = await _valueFactory!();
_boxed = new Boxed() { Value = value };
}
catch (Exception ex)
{
_boxed = new Boxed() { Exception = ExceptionDispatchInfo.Capture(ex) };
}
finally
{
_semaphore = null;
_valueFactory = null;
}
}
}
finally
{
semaphore.Release();
}
}
result = _boxed;
}
result!.Exception?.Throw();
return result.Value!;
}
private class Boxed
{
public T? Value { get; init; }
public ExceptionDispatchInfo? Exception { get; init; }
}
}
@theodorzoulias
Copy link

private Boxed? _boxed;

This field should be declared as volatile, to eliminate the possibility of a thread seeing a partially initialized T instance. See: The need for volatile modifier in double checked locking in .NET.

@ArtemAvramenko
Copy link
Author

@theodorzoulias Thanks, I added volatile also to _semaphore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment