Soenneker.Asyncs.Locks
4.0.62
Prefix Reserved
See the version list below for details.
dotnet add package Soenneker.Asyncs.Locks --version 4.0.62
NuGet\Install-Package Soenneker.Asyncs.Locks -Version 4.0.62
<PackageReference Include="Soenneker.Asyncs.Locks" Version="4.0.62" />
<PackageVersion Include="Soenneker.Asyncs.Locks" Version="4.0.62" />
<PackageReference Include="Soenneker.Asyncs.Locks" />
paket add Soenneker.Asyncs.Locks --version 4.0.62
#r "nuget: Soenneker.Asyncs.Locks, 4.0.62"
#:package Soenneker.Asyncs.Locks@4.0.62
#addin nuget:?package=Soenneker.Asyncs.Locks&version=4.0.62
#tool nuget:?package=Soenneker.Asyncs.Locks&version=4.0.62
Soenneker.Asyncs.Locks
The fastest .NET async lock
This library provides a single primitive: AsyncLock.
Design goal
AsyncLock is built to be the fastest possible correct mutex for real-world .NET systems.
It provides the following guarantees:
Cancellation-safe
- Fully supports cancellation before acquisition and while waiting for both async and sync callers.
- Cancelled waiters are removed immediately, never resumed, and never leaked � with zero impact on the fast path.
Unified async + sync locking
- Async and synchronous callers share the same mutex.
- Ordering is preserved without adapters, wrappers, or duplicated synchronization primitives.
Performance (by design)
- Uncontended acquisition is as close to a single atomic operation as possible
- No allocations, tasks, or state machines unless contention occurs
- Cancellation and disposal logic are completely excluded from the fast path
- Deterministic behavior under contention
Installation
dotnet add package Soenneker.Asyncs.Locks
Usage
Async
await using (await _lock.Lock(ct))
{
// critical section
}
Sync
using (_lock.LockSync())
{
// critical section
}
Try-lock
if (_lock.TryLock(out var releaser))
{
using (releaser)
{
// critical section
}
}
Benchmarks
Async lock acquisition
| Method | Mean | Error | StdDev | Median | Ratio | Allocated |
|---|---|---|---|---|---|---|
| Soenneker.Asyncs.Lock | 10.06 ns | 0.212 ns | 0.393 ns | 10.01 ns | baseline | - |
| SemaphoreSlim | 19.17 ns | 0.406 ns | 0.360 ns | 19.10 ns | 1.91x slower | - |
| Nito.AsyncEx.AsyncLock | 55.32 ns | 1.078 ns | 2.645 ns | 54.81 ns | 5.51x slower | 320 B |
Synchronous lock acquisition
| Method | Mean | Error | StdDev | Median | Ratio | Allocated |
|---|---|---|---|---|---|---|
| Soenneker.Asyncs.Lock | 8.09 ns | 0.179 ns | 0.314 ns | 8.03 ns | baseline | - |
| SemaphoreSlim | 19.49 ns | 0.403 ns | 0.727 ns | 19.09 ns | 2.41x slower | - |
| Nito.AsyncEx.AsyncLock | 48.43 ns | 1.005 ns | 2.915 ns | 48.05 ns | 6.00x slower | 320 B |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Soenneker.Atomics.ValueInts (>= 4.0.22)
- Soenneker.Extensions.Task (>= 4.0.124)
- Soenneker.Queues.Intrusive.ValueMpsc (>= 4.0.27)
NuGet packages (18)
Showing the top 5 NuGet packages that depend on Soenneker.Asyncs.Locks:
| Package | Downloads |
|---|---|
|
Soenneker.Utils.AsyncSingleton
An externally initializing singleton that uses double-check asynchronous locking, with optional async and sync disposal |
|
|
Soenneker.Dictionaries.SingletonKeys
An externally initializing singleton dictionary that uses double-check asynchronous locking, with optional async and sync disposal |
|
|
Soenneker.Blazor.Utils.ModuleImport
A Blazor utility library assisting with asynchronous module loading |
|
|
Soenneker.Blazor.Utils.JsVariable
A Blazor interop library that checks (and waits) for the existence of a JS variable |
|
|
Soenneker.Blazor.Utils.InteropEventListener
Manages the registration, removal, and disposal of .NET object references used for interop event listeners. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.89 | 36,631 | 9/15/2026 |
| 4.0.87 | 703 | 9/15/2026 |
| 4.0.86 | 78,282 | 9/12/2026 |
| 4.0.85 | 218 | 9/12/2026 |
| 4.0.84 | 20,364 | 9/12/2026 |
| 4.0.83 | 23,838 | 9/12/2026 |
| 4.0.82 | 8,181 | 9/12/2026 |
| 4.0.79 | 120,629 | 9/7/2026 |
| 4.0.78 | 103,286 | 9/4/2026 |
| 4.0.77 | 14,369 | 9/3/2026 |
| 4.0.76 | 21,212 | 9/3/2026 |
| 4.0.75 | 100 | 9/3/2026 |
| 4.0.74 | 64,817 | 8/31/2026 |
| 4.0.73 | 38,202 | 8/30/2026 |
| 4.0.72 | 176 | 8/30/2026 |
| 4.0.71 | 11,301 | 8/30/2026 |
| 4.0.70 | 22,415 | 8/29/2026 |
| 4.0.68 | 268,773 | 8/8/2026 |
| 4.0.67 | 33,722 | 8/8/2026 |
| 4.0.62 | 113,099 | 7/19/2026 |
Update dependency Soenneker.Queues.Intrusive.ValueMpsc to 4.0.27 (#202)