Browse Source

Refactor KeyedLock disposal logic and update tests

pull/24502/head
maliming 9 months ago
parent
commit
b06e8a9381
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 37
      framework/src/Volo.Abp.Core/Volo/Abp/Threading/KeyedLock.cs
  2. 4
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/Threading/KeyedLock_Tests.cs

37
framework/src/Volo.Abp.Core/Volo/Abp/Threading/KeyedLock.cs

@ -15,7 +15,7 @@ public static class KeyedLock
public static async Task<IDisposable> LockAsync(object key)
{
return await LockAsync(key, CancellationToken.None).ConfigureAwait(false);
return await LockAsync(key, CancellationToken.None);
}
public static async Task<IDisposable> LockAsync(object key, CancellationToken cancellationToken)
@ -23,7 +23,7 @@ public static class KeyedLock
var semaphore = GetOrCreate(key);
try
{
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
await semaphore.WaitAsync(cancellationToken);
}
catch (OperationCanceledException)
{
@ -36,7 +36,7 @@ public static class KeyedLock
public static async Task<IDisposable?> TryLockAsync(object key)
{
return await TryLockAsync(key, default, CancellationToken.None).ConfigureAwait(false);
return await TryLockAsync(key, default, CancellationToken.None);
}
public static async Task<IDisposable?> TryLockAsync(object key, TimeSpan timeout, CancellationToken cancellationToken = default)
@ -47,11 +47,11 @@ public static class KeyedLock
{
if (timeout == default)
{
acquired = await semaphore.WaitAsync(0, cancellationToken).ConfigureAwait(false);
acquired = await semaphore.WaitAsync(0, cancellationToken);
}
else
{
acquired = await semaphore.WaitAsync(timeout, cancellationToken).ConfigureAwait(false);
acquired = await semaphore.WaitAsync(timeout, cancellationToken);
}
}
catch (OperationCanceledException)
@ -99,9 +99,17 @@ public static class KeyedLock
private sealed class Releaser(object key) : IDisposable
{
private int _disposed;
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, 1) == 1)
{
return;
}
RefCounted<SemaphoreSlim> item;
var shouldDispose = false;
lock (SemaphoreSlims)
{
if (!SemaphoreSlims.TryGetValue(key, out item!))
@ -109,19 +117,10 @@ public static class KeyedLock
return;
}
--item.RefCount;
}
item.Value.Release();
bool shouldDispose = false;
lock (SemaphoreSlims)
{
if (SemaphoreSlims.TryGetValue(key, out var current) && ReferenceEquals(current, item))
if (item.RefCount == 0)
{
if (item.RefCount == 0)
{
SemaphoreSlims.Remove(key);
shouldDispose = true;
}
SemaphoreSlims.Remove(key);
shouldDispose = true;
}
}
@ -129,6 +128,10 @@ public static class KeyedLock
{
item.Value.Dispose();
}
else
{
item.Value.Release();
}
}
}

4
framework/test/Volo.Abp.Core.Tests/Volo/Abp/Threading/KeyedLock_Tests.cs

@ -56,13 +56,13 @@ public class KeyedLock_Tests
});
// While holding the outer lock, inner waiter should not complete
await Task.Delay(150);
await Task.Delay(200);
inner.IsCompleted.ShouldBeFalse();
}
// After releasing, inner should complete; elapsed >= hold time
await inner;
sw.ElapsedMilliseconds.ShouldBeGreaterThanOrEqualTo(150);
sw.ElapsedMilliseconds.ShouldBeGreaterThanOrEqualTo(180);
}
[Fact]

Loading…
Cancel
Save