diff --git a/AsyncKeyedLock/AsyncKeyedLock.csproj b/AsyncKeyedLock/AsyncKeyedLock.csproj
index 5fab03b..b620c7e 100644
--- a/AsyncKeyedLock/AsyncKeyedLock.csproj
+++ b/AsyncKeyedLock/AsyncKeyedLock.csproj
@@ -8,16 +8,16 @@
https://github.com/MarkCiliaVincenti/AsyncKeyedLock
MIT
MIT
- 6.2.5
+ 6.2.6
logo.png
- Minor optimization.
+ Cleaning pooling and aggressively inlining locking methods.
An asynchronous .NET Standard 2.0 library that allows you to lock based on a key (keyed semaphores), limiting concurrent threads sharing the same key to a specified number, with optional pooling for reducing memory allocations.
- © 2023 Mark Cilia Vincenti
+ © 2024 Mark Cilia Vincenti
async,lock,key,keyed,semaphore,striped,dictionary,concurrentdictionary,pooling,duplicate,synchronization
git
false
- 6.2.5.0
- 6.2.5.0
+ 6.2.6.0
+ 6.2.6.0
README.md
true
True
diff --git a/AsyncKeyedLock/AsyncKeyedLockDictionary.cs b/AsyncKeyedLock/AsyncKeyedLockDictionary.cs
index 1839d6f..4de2ca4 100644
--- a/AsyncKeyedLock/AsyncKeyedLockDictionary.cs
+++ b/AsyncKeyedLock/AsyncKeyedLockDictionary.cs
@@ -24,7 +24,7 @@ public AsyncKeyedLockDictionary(AsyncKeyedLockOptions options) : base()
if (options.PoolSize > 0)
{
PoolingEnabled = true;
- _pool = new AsyncKeyedLockPool((key) => new AsyncKeyedLockReleaser(key, new SemaphoreSlim(MaxCount, MaxCount), this), options.PoolSize, options.PoolInitialFill);
+ _pool = new AsyncKeyedLockPool(this, options.PoolSize, options.PoolInitialFill);
}
}
@@ -40,7 +40,7 @@ public AsyncKeyedLockDictionary(AsyncKeyedLockOptions options, IEqualityComparer
if (options.PoolSize > 0)
{
PoolingEnabled = true;
- _pool = new AsyncKeyedLockPool((key) => new AsyncKeyedLockReleaser(key, new SemaphoreSlim(MaxCount, MaxCount), this), options.PoolSize, options.PoolInitialFill);
+ _pool = new AsyncKeyedLockPool(this, options.PoolSize, options.PoolInitialFill);
}
}
@@ -56,7 +56,7 @@ public AsyncKeyedLockDictionary(AsyncKeyedLockOptions options, int concurrencyLe
if (options.PoolSize > 0)
{
PoolingEnabled = true;
- _pool = new AsyncKeyedLockPool((key) => new AsyncKeyedLockReleaser(key, new SemaphoreSlim(MaxCount, MaxCount), this), options.PoolSize, options.PoolInitialFill);
+ _pool = new AsyncKeyedLockPool(this, options.PoolSize, options.PoolInitialFill);
}
}
@@ -72,7 +72,7 @@ public AsyncKeyedLockDictionary(AsyncKeyedLockOptions options, int concurrencyLe
if (options.PoolSize > 0)
{
PoolingEnabled = true;
- _pool = new AsyncKeyedLockPool((key) => new AsyncKeyedLockReleaser(key, new SemaphoreSlim(MaxCount, MaxCount), this), options.PoolSize, options.PoolInitialFill);
+ _pool = new AsyncKeyedLockPool(this, options.PoolSize, options.PoolInitialFill);
}
}
diff --git a/AsyncKeyedLock/AsyncKeyedLockOptions.cs b/AsyncKeyedLock/AsyncKeyedLockOptions.cs
index 1f47b73..36677fc 100644
--- a/AsyncKeyedLock/AsyncKeyedLockOptions.cs
+++ b/AsyncKeyedLock/AsyncKeyedLockOptions.cs
@@ -11,7 +11,9 @@ public sealed class AsyncKeyedLockOptions
public int MaxCount { get; set; } = 1;
///
- /// The size of the pool to use in order for generated objects to be reused. Defaults to 0 (disabled).
+ /// The size of the pool to use in order for generated objects to be reused. This is NOT a concurrency limit,
+ /// but if the pool is empty then a new object will be created rather than waiting for an object to return to
+ /// the pool. Defaults to 0 (disabled) but strongly recommended to use.
///
public int PoolSize { get; set; } = 0;
@@ -24,7 +26,9 @@ public sealed class AsyncKeyedLockOptions
/// Initializes options for the constructors
///
/// The maximum number of requests for the semaphore that can be granted concurrently. Defaults to 1.
- /// The size of the pool to use in order for generated objects to be reused. Defaults to 0 (disabled).
+ /// The size of the pool to use in order for generated objects to be reused. This is NOT a concurrency limit,
+ /// but if the pool is empty then a new object will be created rather than waiting for an object to return to
+ /// the pool. Defaults to 0 (disabled) but strongly recommended to use.
/// The number of items to fill the pool with during initialization. Defaults to -1 (fill up to pool size).
public AsyncKeyedLockOptions(int maxCount = 1, int poolSize = 0, int poolInitialFill = -1)
{
diff --git a/AsyncKeyedLock/AsyncKeyedLockPool.cs b/AsyncKeyedLock/AsyncKeyedLockPool.cs
index 6f8aa64..10aa907 100644
--- a/AsyncKeyedLock/AsyncKeyedLockPool.cs
+++ b/AsyncKeyedLock/AsyncKeyedLockPool.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
+using System.Threading;
namespace AsyncKeyedLock
{
@@ -9,10 +10,14 @@ internal sealed class AsyncKeyedLockPool : IDisposable
private readonly BlockingCollection> _objects;
private readonly Func> _objectGenerator;
- public AsyncKeyedLockPool(Func> objectGenerator, int capacity, int initialFill = -1)
+ public AsyncKeyedLockPool(AsyncKeyedLockDictionary asyncKeyedLockDictionary, int capacity, int initialFill = -1)
{
_objects = new BlockingCollection>(new ConcurrentBag>(), capacity);
- _objectGenerator = objectGenerator;
+ _objectGenerator = (key) => new AsyncKeyedLockReleaser(
+ key,
+ new SemaphoreSlim(asyncKeyedLockDictionary.MaxCount, asyncKeyedLockDictionary.MaxCount),
+ asyncKeyedLockDictionary);
+
if (initialFill < 0)
{
for (int i = 0; i < capacity; ++i)
diff --git a/AsyncKeyedLock/AsyncKeyedLocker.cs b/AsyncKeyedLock/AsyncKeyedLocker.cs
index e4b06aa..d5a81d0 100644
--- a/AsyncKeyedLock/AsyncKeyedLocker.cs
+++ b/AsyncKeyedLock/AsyncKeyedLocker.cs
@@ -335,6 +335,7 @@ public AsyncKeyedLocker(Action options, int concurrencyLe
///
/// The key to lock on.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IDisposable Lock(TKey key)
{
var releaser = GetOrAdd(key);
@@ -348,6 +349,7 @@ public IDisposable Lock(TKey key)
/// The key to lock on.
/// The to observe.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IDisposable Lock(TKey key, CancellationToken cancellationToken)
{
var releaser = GetOrAdd(key);
@@ -370,6 +372,7 @@ public IDisposable Lock(TKey key, CancellationToken cancellationToken)
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// An out parameter showing whether or not the semaphore was entered.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IDisposable Lock(TKey key, int millisecondsTimeout, out bool entered)
{
var releaser = GetOrAdd(key);
@@ -390,6 +393,7 @@ public IDisposable Lock(TKey key, int millisecondsTimeout, out bool entered)
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// An out parameter showing whether or not the semaphore was entered.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IDisposable Lock(TKey key, TimeSpan timeout, out bool entered)
{
var releaser = GetOrAdd(key);
@@ -411,6 +415,7 @@ public IDisposable Lock(TKey key, TimeSpan timeout, out bool entered)
/// The to observe.
/// An out parameter showing whether or not the semaphore was entered.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IDisposable Lock(TKey key, int millisecondsTimeout, CancellationToken cancellationToken, out bool entered)
{
var releaser = GetOrAdd(key);
@@ -441,6 +446,7 @@ public IDisposable Lock(TKey key, int millisecondsTimeout, CancellationToken can
/// The to observe.
/// An out parameter showing whether or not the semaphore was entered.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IDisposable Lock(TKey key, TimeSpan timeout, CancellationToken cancellationToken, out bool entered)
{
var releaser = GetOrAdd(key);
@@ -472,6 +478,7 @@ public IDisposable Lock(TKey key, TimeSpan timeout, CancellationToken cancellati
/// The synchronous action.
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryLock(TKey key, Action action, int millisecondsTimeout)
{
var releaser = GetOrAdd(key);
@@ -499,6 +506,7 @@ public bool TryLock(TKey key, Action action, int millisecondsTimeout)
/// The synchronous action.
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryLock(TKey key, Action action, TimeSpan timeout)
{
var releaser = GetOrAdd(key);
@@ -527,6 +535,7 @@ public bool TryLock(TKey key, Action action, TimeSpan timeout)
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// The to observe.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryLock(TKey key, Action action, int millisecondsTimeout, CancellationToken cancellationToken)
{
var releaser = GetOrAdd(key);
@@ -563,6 +572,7 @@ public bool TryLock(TKey key, Action action, int millisecondsTimeout, Cancellati
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// The to observe.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryLock(TKey key, Action action, TimeSpan timeout, CancellationToken cancellationToken)
{
var releaser = GetOrAdd(key);
@@ -601,6 +611,7 @@ public bool TryLock(TKey key, Action action, TimeSpan timeout, CancellationToken
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, int millisecondsTimeout, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -629,6 +640,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, int milliseco
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, int millisecondsTimeout, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -657,6 +669,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, int millise
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan timeout, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -685,6 +698,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan time
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan timeout, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -714,6 +728,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan ti
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, int millisecondsTimeout, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -751,6 +766,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, int milliseco
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, int millisecondsTimeout, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -788,6 +804,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, int millise
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan timeout, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -825,6 +842,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan time
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan timeout, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -864,6 +882,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan ti
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, int millisecondsTimeout, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -892,6 +911,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, int milliseco
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, int millisecondsTimeout, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -920,6 +940,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, int millise
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan timeout, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -948,6 +969,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan time
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan timeout, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -977,6 +999,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan ti
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, int millisecondsTimeout, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1014,6 +1037,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, int milliseco
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, int millisecondsTimeout, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1051,6 +1075,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, int millise
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan timeout, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1088,6 +1113,7 @@ public async ValueTask TryLockAsync(TKey key, Action action, TimeSpan time
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// False if timed out, true if it successfully entered.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan timeout, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1125,6 +1151,7 @@ public async ValueTask TryLockAsync(TKey key, Func task, TimeSpan ti
/// The key to lock on.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask LockAsync(TKey key, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -1139,6 +1166,7 @@ public async ValueTask LockAsync(TKey key, bool continueOnCapturedC
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask LockAsync(TKey key, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -1161,6 +1189,7 @@ public async ValueTask LockAsync(TKey key, CancellationToken cancel
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, int millisecondsTimeout, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -1174,6 +1203,7 @@ public async ValueTask> LockAsync(TKey key,
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, TimeSpan timeout, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -1188,6 +1218,7 @@ public async ValueTask> LockAsync(TKey key,
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, int millisecondsTimeout, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -1210,6 +1241,7 @@ public async ValueTask> LockAsync(TKey key,
/// The to observe.
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false. Defaults to false.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, TimeSpan timeout, CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
var releaser = GetOrAdd(key);
@@ -1233,6 +1265,7 @@ public async ValueTask> LockAsync(TKey key,
/// The key to lock on.
/// Options used to configure how awaits on this task are performed.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask LockAsync(TKey key, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1247,6 +1280,7 @@ public async ValueTask LockAsync(TKey key, ConfigureAwaitOptions co
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// A disposable value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask LockAsync(TKey key, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1269,6 +1303,7 @@ public async ValueTask LockAsync(TKey key, CancellationToken cancel
/// The number of milliseconds to wait, (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.
/// Options used to configure how awaits on this task are performed.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, int millisecondsTimeout, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1282,6 +1317,7 @@ public async ValueTask> LockAsync(TKey key,
/// A that represents the number of milliseconds to wait, a that represents -1 milliseconds to wait indefinitely, or a that represents 0 milliseconds to test the wait handle and return immediately.
/// Options used to configure how awaits on this task are performed.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, TimeSpan timeout, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1296,6 +1332,7 @@ public async ValueTask> LockAsync(TKey key,
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, int millisecondsTimeout, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1318,6 +1355,7 @@ public async ValueTask> LockAsync(TKey key,
/// The to observe.
/// Options used to configure how awaits on this task are performed.
/// A disposable value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public async ValueTask> LockAsync(TKey key, TimeSpan timeout, CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
var releaser = GetOrAdd(key);
@@ -1339,6 +1377,7 @@ public async ValueTask> LockAsync(TKey key,
///
/// The key requests are locked on.
/// if the key is in use; otherwise, false.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsInUse(TKey key)
{
if (!_dictionary.TryGetValue(key, out var result))
@@ -1376,6 +1415,7 @@ public int GetCount(TKey key)
///
/// The key requests are locked on.
/// The number of requests concurrently locked for a given key.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetRemainingCount(TKey key)
{
if (_dictionary.TryGetValue(key, out var releaser))
@@ -1390,6 +1430,7 @@ public int GetRemainingCount(TKey key)
///
/// The key requests are locked on.
/// The number of remaining threads that can enter the lock for a given key.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetCurrentCount(TKey key)
{
return MaxCount - GetRemainingCount(key);
@@ -1398,6 +1439,7 @@ public int GetCurrentCount(TKey key)
///
/// Disposes the AsyncKeyedLocker.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
_dictionary.Dispose();
diff --git a/README.md b/README.md
index 56faab9..18cfba0 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,25 @@ For example, suppose you were processing financial transactions, but while worki
The library uses two very different methods for locking, one using an underlying `ConcurrentDictionary` that's cleaned up after use whilst the other using a technique called striped locking. Both have their advantages and disadvantages, and in order to help you choose you are highly recommended to read about it in the [wiki](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki).
## Installation and usage
+Using this library is straightforward. Here's a simple example:
+```csharp
+private static readonly AsyncKeyedLocker _asyncKeyedLocker = new(o =>
+ {
+ o.PoolSize = 20; // this is NOT a concurrency limit
+ o.PoolInitialFill = 1;
+ });
+
+...
+
+using (await _asyncKeyedLocker.LockAsync("test123"))
+{
+ ...
+}
+```
+
The documentation can be found in our [wiki](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki).
+Usage
+
## Credits
Check out our [list of contributors](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/blob/master/CONTRIBUTORS.md)!