Skip to content

Commit

Permalink
Fixes CancellationToken issues and adding TryLockAsync methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkCiliaVincenti committed Oct 26, 2022
1 parent a961494 commit a916794
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 7 deletions.
4 changes: 4 additions & 0 deletions AsyncKeyedLock.Tests/AsyncKeyedLock.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AsyncKeyedLock\AsyncKeyedLock.csproj" />
</ItemGroup>

</Project>
8 changes: 4 additions & 4 deletions AsyncKeyedLock/AsyncKeyedLock.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
<RepositoryUrl>https://github.com/MarkCiliaVincenti/AsyncKeyedLock.git</RepositoryUrl>
<PackageProjectUrl>https://github.com/MarkCiliaVincenti/AsyncKeyedLock</PackageProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Version>3.2.2</Version>
<Version>3.2.3</Version>
<PackageIcon>logo.png</PackageIcon>
<PackageReleaseNotes>Fixes CancellationToken issue and adding TryLockAsync methods.</PackageReleaseNotes>
<PackageReleaseNotes>Fixes CancellationToken issues and adding TryLockAsync methods.</PackageReleaseNotes>
<Description>An asynchronous .NET Standard 2.0 library that allows you to lock based on a key (keyed semaphores), only allowing a defined number of concurrent threads that share the same key.</Description>
<Copyright>© 2022 Mark Cilia Vincenti</Copyright>
<PackageTags>async,lock,key,semaphore,dictionary</PackageTags>
<RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AssemblyVersion>3.2.2.0</AssemblyVersion>
<FileVersion>3.2.2.0</FileVersion>
<AssemblyVersion>3.2.3.0</AssemblyVersion>
<FileVersion>3.2.3.0</FileVersion>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IsPackable>true</IsPackable>
<IsTrimmable>true</IsTrimmable>
Expand Down
2 changes: 1 addition & 1 deletion AsyncKeyedLock/AsyncKeyedLockReferenceCounter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed class AsyncKeyedLockReferenceCounter<TKey>
/// <summary>
/// The reference count
/// </summary>
public int ReferenceCount { get; set; }
public int ReferenceCount { get; set; } = 1;

private readonly SemaphoreSlim _semaphoreSlim;

Expand Down
4 changes: 2 additions & 2 deletions AsyncKeyedLock/AsyncKeyedLocker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public AsyncKeyedLocker(int maxCount)
public IDisposable Lock(TKey key)
{
var referenceCounter = SemaphoreSlims.GetOrAdd(key);
referenceCounter.SemaphoreSlim.WaitAsync();
referenceCounter.SemaphoreSlim.Wait();
return referenceCounter.Releaser;
}

Expand All @@ -86,7 +86,7 @@ public IDisposable Lock(TKey key, CancellationToken cancellationToken)
var referenceCounter = SemaphoreSlims.GetOrAdd(key);
try
{
referenceCounter.SemaphoreSlim.WaitAsync(cancellationToken);
referenceCounter.SemaphoreSlim.Wait(cancellationToken);
}
catch (OperationCanceledException)
{
Expand Down
82 changes: 82 additions & 0 deletions AsyncKeyedLock/IAsyncKeyedLocker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public interface IAsyncKeyedLocker<TKey>
/// </summary>
int MaxCount { get; set; }

#region Synchronous
/// <summary>
/// Synchronously lock based on a key.
/// </summary>
Expand Down Expand Up @@ -107,7 +108,87 @@ public interface IAsyncKeyedLocker<TKey>
/// <param name="success">False if timed out, true if it successfully entered.</param>
/// <returns>A disposable value.</returns>
IDisposable Lock(TKey key, TimeSpan timeout, CancellationToken cancellationToken, out bool success);
#endregion Synchronous

#region AsynchronousTry
/// <summary>
/// Asynchronously lock based on a key, setting a limit for the number of milliseconds to wait, and if not timed out, scynchronously execute an action and release.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="action">The synchronous action.</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, <see cref="Timeout.Infinite"/> (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Action action, int millisecondsTimeout);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the number of milliseconds to wait, and if not timed out, scynchronously execute an action and release.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="task">The asynchronous task.</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, <see cref="Timeout.Infinite"/> (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Func<Task> task, int millisecondsTimeout);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the <see cref="System.TimeSpan"/> to wait, and if not timed out, scynchronously execute an action and release.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="action">The synchronous action.</param>
/// <param name="timeout">A <see cref="TimeSpan"/> that represents the number of milliseconds to wait, a <see cref="TimeSpan"/> that represents -1 milliseconds to wait indefinitely, or a <see cref="TimeSpan"/> that represents 0 milliseconds to test the wait handle and return immediately.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Action action, TimeSpan timeout);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the <see cref="System.TimeSpan"/> to wait, and if not timed out, scynchronously execute an action and release.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="task">The asynchronous task.</param>
/// <param name="timeout">A <see cref="TimeSpan"/> that represents the number of milliseconds to wait, a <see cref="TimeSpan"/> that represents -1 milliseconds to wait indefinitely, or a <see cref="TimeSpan"/> that represents 0 milliseconds to test the wait handle and return immediately.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Func<Task> task, TimeSpan timeout);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the number of milliseconds to wait, and if not timed out, scynchronously execute an action and release, while observing a <see cref="CancellationToken"/>.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="action">The synchronous action.</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, <see cref="Timeout.Infinite"/> (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Action action, int millisecondsTimeout, CancellationToken cancellationToken);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the number of milliseconds to wait, and if not timed out, scynchronously execute an action and release, while observing a <see cref="CancellationToken"/>.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="task">The asynchronous task.</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, <see cref="Timeout.Infinite"/> (-1) to wait indefinitely, or zero to test the state of the wait handle and return immediately.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Func<Task> task, int millisecondsTimeout, CancellationToken cancellationToken);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the <see cref="System.TimeSpan"/> to wait, and if not timed out, scynchronously execute an action and release, while observing a <see cref="CancellationToken"/>.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="action">The synchronous action.</param>
/// <param name="timeout">A <see cref="TimeSpan"/> that represents the number of milliseconds to wait, a <see cref="TimeSpan"/> that represents -1 milliseconds to wait indefinitely, or a <see cref="TimeSpan"/> that represents 0 milliseconds to test the wait handle and return immediately.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Action action, TimeSpan timeout, CancellationToken cancellationToken);

/// <summary>
/// Asynchronously lock based on a key, setting a limit for the <see cref="System.TimeSpan"/> to wait, and if not timed out, scynchronously execute an action and release, while observing a <see cref="CancellationToken"/>.
/// </summary>
/// <param name="key">The key to lock on.</param>
/// <param name="task">The asynchronous task.</param>
/// <param name="timeout">A <see cref="TimeSpan"/> that represents the number of milliseconds to wait, a <see cref="TimeSpan"/> that represents -1 milliseconds to wait indefinitely, or a <see cref="TimeSpan"/> that represents 0 milliseconds to test the wait handle and return immediately.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>False if timed out, true if it successfully entered.</returns>
Task<bool> TryLockAsync(TKey key, Func<Task> task, TimeSpan timeout, CancellationToken cancellationToken);
#endregion AsynchronousTry

#region Asynchronous
/// <summary>
/// Asynchronously lock based on a key.
/// </summary>
Expand Down Expand Up @@ -156,6 +237,7 @@ public interface IAsyncKeyedLocker<TKey>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>A disposable value.</returns>
Task<IDisposable> LockAsync(TKey key, TimeSpan timeout, CancellationToken cancellationToken);
#endregion

/// <summary>
/// Checks whether or not there is a thread making use of a keyed lock.
Expand Down

0 comments on commit a916794

Please sign in to comment.