Skip to content

Commit 33fa7a8

Browse files
Merge pull request #73941 from CyrusNajmabadi/asyncLock
2 parents e88d573 + f86796c commit 33fa7a8

File tree

1 file changed

+11
-7
lines changed
  • src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities

1 file changed

+11
-7
lines changed

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncLazy`1.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ private sealed class AsyncLazyImpl<TData> : AsyncLazy<T>
6161
private Task<T>? _cachedResult;
6262

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

7171
/// <summary>
7272
/// The hash set of all currently outstanding asynchronous requests. Null if there are no requests,
@@ -136,7 +136,10 @@ public static AsyncLazy<T> CreateImpl(
136136
/// </summary>
137137
private WaitThatValidatesInvariants TakeLock(CancellationToken cancellationToken)
138138
{
139-
s_gate.Wait(cancellationToken);
139+
Contract.ThrowIfTrue(Monitor.IsEntered(SyncObject), "Attempt to take the lock while already holding it!");
140+
141+
cancellationToken.ThrowIfCancellationRequested();
142+
Monitor.Enter(SyncObject);
140143
AssertInvariants_NoLock();
141144
return new WaitThatValidatesInvariants(this);
142145
}
@@ -146,7 +149,8 @@ private readonly struct WaitThatValidatesInvariants(AsyncLazyImpl<TData> asyncLa
146149
public void Dispose()
147150
{
148151
asyncLazy.AssertInvariants_NoLock();
149-
s_gate.Release();
152+
Contract.ThrowIfFalse(Monitor.IsEntered(asyncLazy.SyncObject));
153+
Monitor.Exit(asyncLazy.SyncObject);
150154
}
151155
}
152156

0 commit comments

Comments
 (0)