Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change AsyncLazy from NonReentrantLock to a simple monitor enter #73941

Merged
merged 4 commits into from
Jun 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ private sealed class AsyncLazyImpl<TData> : AsyncLazy<T>
private Task<T>? _cachedResult;

/// <summary>
/// Mutex used to protect reading and writing to all mutable objects and fields. Traces
/// indicate that there's negligible contention on this lock, hence we can save some memory
/// by using a single lock for all AsyncLazy instances. Only trivial and non-reentrant work
/// should be done while holding the lock.
/// Mutex used to protect reading and writing to all mutable objects and fields. Traces indicate that there's
/// negligible contention on this lock (and on any particular async-lazy in general), hence we can save some
/// memory by using ourselves as the lock, even though this may inhibit cancellation. Work done while holding
/// the lock should be kept to a minimum.
/// </summary>
private static readonly NonReentrantLock s_gate = new(useThisInstanceForSynchronization: true);
private object SyncObject => this;

/// <summary>
/// The hash set of all currently outstanding asynchronous requests. Null if there are no requests,
Expand Down Expand Up @@ -136,7 +136,10 @@ public static AsyncLazy<T> CreateImpl(
/// </summary>
private WaitThatValidatesInvariants TakeLock(CancellationToken cancellationToken)
{
s_gate.Wait(cancellationToken);
Contract.ThrowIfTrue(Monitor.IsEntered(SyncObject), "Attempt to take the lock while already holding it!");

cancellationToken.ThrowIfCancellationRequested();
Monitor.Enter(SyncObject);
AssertInvariants_NoLock();
return new WaitThatValidatesInvariants(this);
}
Expand All @@ -146,7 +149,8 @@ private readonly struct WaitThatValidatesInvariants(AsyncLazyImpl<TData> asyncLa
public void Dispose()
{
asyncLazy.AssertInvariants_NoLock();
s_gate.Release();
Contract.ThrowIfFalse(Monitor.IsEntered(asyncLazy.SyncObject));
Monitor.Exit(asyncLazy.SyncObject);
}
}

Expand Down
Loading