Skip to content

Commit 0000326

Browse files
committed
Use SemaphoreSlim in AsyncLockQueueDictionary
1 parent dfeb068 commit 0000326

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

Synchronisation.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace AsyncToSyncCodeRoundtripSynchroniserMonitor
1010
{
1111
public class AsyncLockQueueDictionary
1212
{
13-
private readonly object DictionaryAccessMutex = new object();
13+
//private readonly object DictionaryAccessMutex = new object();
14+
private readonly SemaphoreSlim DictionaryAccessMutex = new SemaphoreSlim(1, 1);
1415
private readonly Dictionary<string, AsyncLockWithCount> LockQueueDictionary = new Dictionary<string, AsyncLockWithCount>();
1516

1617
public sealed class AsyncLockWithCount
@@ -25,7 +26,7 @@ public AsyncLockWithCount()
2526
}
2627
}
2728

28-
public sealed class LockDictReleaser : IDisposable
29+
public sealed class LockDictReleaser : IDisposable //TODO: implement IAsyncDisposable in .NET 5.0
2930
{
3031
private readonly string Name;
3132
private readonly AsyncLockWithCount LockEntry;
@@ -50,7 +51,9 @@ private void ReleaseLock(string name, AsyncLockWithCount lockEntry, IDisposable
5051
{
5152
lockHandle.Dispose();
5253

53-
lock (DictionaryAccessMutex)
54+
//lock (DictionaryAccessMutex)
55+
DictionaryAccessMutex.Wait();
56+
try
5457
{
5558
lockEntry.WaiterCount--;
5659
Debug.Assert(lockEntry.WaiterCount >= 0);
@@ -60,29 +63,39 @@ private void ReleaseLock(string name, AsyncLockWithCount lockEntry, IDisposable
6063
LockQueueDictionary.Remove(name);
6164
}
6265
}
66+
finally
67+
{
68+
DictionaryAccessMutex.Release();
69+
}
6370
}
6471

6572
public async Task<LockDictReleaser> LockAsync(string name, CancellationToken cancellationToken = default(CancellationToken))
6673
{
6774
AsyncLockWithCount lockEntry;
68-
lock (DictionaryAccessMutex)
75+
//lock (DictionaryAccessMutex)
76+
await DictionaryAccessMutex.WaitAsync(cancellationToken);
77+
try
6978
{
7079
if (!LockQueueDictionary.TryGetValue(name, out lockEntry))
7180
{
72-
lockEntry = new AsyncLockWithCount();
81+
lockEntry = new AsyncLockWithCount();
7382
LockQueueDictionary.Add(name, lockEntry);
7483
}
7584
else
7685
{
7786
lockEntry.WaiterCount++; //NB! must be done inside the lock and BEFORE waiting for the lock
7887
}
7988
}
89+
finally
90+
{
91+
DictionaryAccessMutex.Release();
92+
}
8093

8194
var lockHandle = await lockEntry.LockEntry.LockAsync(cancellationToken);
8295
return new LockDictReleaser(name, lockEntry, lockHandle, this);
8396
}
8497

85-
public sealed class MultiLockDictReleaser : IDisposable
98+
public sealed class MultiLockDictReleaser : IDisposable //TODO: implement IAsyncDisposable in .NET 5.0
8699
{
87100
private readonly LockDictReleaser[] Releasers;
88101

@@ -111,7 +124,7 @@ public void Dispose()
111124

112125
//NB! in order to avoid deadlocks, always take the locks in deterministic order
113126
names.Sort(StringComparer.InvariantCultureIgnoreCase);
114-
127+
115128
var releaser1 = await this.LockAsync(names[0], cancellationToken);
116129
var releaser2 = name1 != name2 ? await this.LockAsync(names[1], cancellationToken) : null;
117130

0 commit comments

Comments
 (0)