AsyncReaderWriterLockSlim 1.0.0
dotnet add package AsyncReaderWriterLockSlim --version 1.0.0
NuGet\Install-Package AsyncReaderWriterLockSlim -Version 1.0.0
<PackageReference Include="AsyncReaderWriterLockSlim" Version="1.0.0" />
paket add AsyncReaderWriterLockSlim --version 1.0.0
#r "nuget: AsyncReaderWriterLockSlim, 1.0.0"
// Install AsyncReaderWriterLockSlim as a Cake Addin #addin nuget:?package=AsyncReaderWriterLockSlim&version=1.0.0 // Install AsyncReaderWriterLockSlim as a Cake Tool #tool nuget:?package=AsyncReaderWriterLockSlim&version=1.0.0
AsyncReaderWriterLockSlim
This is an alternative to .NET's
ReaderWriterLockSlim
with a similar functionality, but can be used in async methods. Due to its async-readiness, it
does not support recursive locks (see section Differences).
Another alternative: https://dotnet.github.io/dotNext/api/DotNext.Threading.AsyncReaderWriterLock.html from https://github.com/dotnet/dotNext
Lock Modes
The lock can have different modes:
- Read mode: One or more read mode locks can be active at a time while no write mode lock is active.
- Write mode: One write mode lock can be active at a time while no other write mode locks and no other read mode locks are active.
When a task or thread ("execution flow") tries to enter a write mode lock while at least one read mode lock is active, it is blocked until the last read mode lock is released.
When a task or thread tries to enter a read mode lock while a write mode lock is active, it is blocked until the write mode lock is released.
If, while other read mode locks are active and the current task or thread waits to enter the write mode lock, another task or thread tries to enter a read mode lock, it is blocked until the current task or thread released the write mode lock (or canceled the wait operation), which means writers are favored in this case.
Also, when a write mode lock is released while there are one or more execution flows trying to enter a write mode lock and also one or more execution flows trying to enter a read mode lock, writers are favored.
Lock Methods
The lock provides synchronous Enter...()
methods for the different lock modes that block
until the lock has been acquired, and asynchronous Enter...Async()
methods that
"block asynchronously" by returning a
Task
that
will complete once the lock has been acquired.
For each Enter...()
and Enter...Async()
method there is also a TryEnter...()
and
TryEnter...Async()
method that allow you to specify an integer time-out, and return a Boolean
that indicates if the lock could be acquired within that time-out.
You must make sure to call the corresponding Exit...()
method to release the lock once you
don't need it anymore.
Additionally, the AsyncReaderWriterLockSlimExtension
class contains extension methods
that return an IDisposable
so that the lock can be used with a using
block.
Performance Considerations
When using the AsyncReaderWriterLockSlim
for write mode locks only, performance is
significantly slower than simply using a
SemaphoreSlim
due to the additional overhead. Therefore, use the AsyncReaderWriterLockSlim
only
when there are far more readers than writers.
Differences to ReaderWriterLockSlim
This implementation has the following differences to .NET's
ReaderWriterLockSlim
:
- The lock is not thread-affine, which means one thread can enter the lock, and a different
thread can release it. This allows you to use the lock in an async method with a
await
operator between entering and releasing the lock. - Additionally to synchronous methods like
EnterReadLock
, it has asynchronous methods likeEnterReadLockAsync
which can be called in async methods, so that the current thread is not blocked while waiting for the lock. - You can specify a
CancellationToken
when entering a lock to cancel the wait operation. - Because this lock is not thread-affine, recursive locks are not supported (which also means they cannot be detected). In order for the lock to work correctly, you must not recursively enter the lock from the same execution flow.
- The lock does not support upgradeable read mode locks that can be upgraded to a write mode lock, due to the complexity this would add.
Differences to Nito.AsyncEx.AsyncReaderWriterLock
This implementation has the following differences to Nito.AsyncEx'
AsyncReaderWriterLock
:
- Instead of methods that return an
IDisposable
, it hasEnter...()
andExit...()
methods similar to .NET'sReaderWriterLockSlim
. However, the classAsyncReaderWriterLockSlimExtension
provides extension methods that return anIDisposable
. - Additionally to providing a
CancellationToken
that allows you to cancel the wait operation, you can supply an integer time-out to theTryEnter...()
methods. - When calling one of the
Enter...()
methods with an already canceledCancellationToken
, the method does not try to acquire the lock, but instead throws aOperationCanceledException
, which matches the behavior ofSemaphoreSlim
. <br> To try to acquire the lock without blocking, you can call one of theTry...
methods without specifying a timeout (or specify a timeout of0
). - You can downgrade a write mode lock to a read mode lock by calling
DowngradeWriteLockToReadLock()
. - Non-async methods do not require a ThreadPool thread to run the unblock logic; instead all code is executed in the thread that called the synchronous method.<br> This means e.g. synchronous methods can still work even when the ThreadPool (used for async task continuations) is currently exhausted, but only if you didn't call async methods at the same time that are still waiting to get the lock.
- The lock is not fair (just as the underlying
SemaphoreSlim
), which means there is no guarantee in which order threads will acquire the lock (e.g. if multiple threads want to get a write lock at the same time using synchronous methods).<br> Fairness can actually lead to problems like lock convoys, and shouldn't be needed in most cases.
Additional Infos
Note: The supported maximum number of concurrent locks in read mode is limited to int.MaxValue
(2147483647).
The lock internally uses
SemaphoreSlim
to implement wait functionality.
API Surface
Method | Description |
---|---|
Dispose () |
Releases all resources used by the AsyncReaderWriterLockSlim . |
EnterReadLock (CancellationToken) |
Enters the lock in read mode. |
EnterReadLockAsync (CancellationToken) |
Asynchronously enters the lock in read mode. |
TryEnterReadLock (Int32, CancellationToken) |
Tries to enter the lock in read mode, with an optional integer time-out. |
TryEnterReadLockAsync (Int32, CancellationToken) |
Tries to asynchronously enter the lock in read mode, with an optional integer time-out. |
EnterWriteLock (CancellationToken) |
Enters the lock in write mode. |
EnterWriteLockAsync (CancellationToken) |
Asynchronously enters the lock in write mode. |
TryEnterWriteLock (Int32, CancellationToken) |
Tries to enter the lock in write mode, with an optional integer time-out. |
TryEnterWriteLockAsync (Int32, CancellationToken) |
Tries to asynchronously enter the lock in write mode, with an optional integer time-out. |
DowngradeWriteLockToReadLock () |
Downgrades the lock from write mode to read mode. |
ExitReadLock () |
Exits read mode. |
ExitWriteLock () |
Exits write mode. |
Examples
Enter the lock in read mode within an async method:
private async Task TestReadModeAsync(AsyncReaderWriterLockSlim asyncLock)
{
// Asynchronously enter the lock in read mode. The task completes after the lock
// has been acquired.
await asyncLock.EnterReadLockAsync();
try
{
// Use Task.Delay to simulate asynchronous work, which means a different thread
// might continue execution after this point.
await Task.Delay(200);
}
finally
{
asyncLock.ExitReadLock();
}
}
Enter the lock in read mode within an async method within an using
block:
private async Task TestReadModeAsync(AsyncReaderWriterLockSlim asyncLock)
{
// Asynchronously enter the lock in read mode. The task completes after the lock
// has been acquired.
// As the Get...() methods return a IDisposeable, you can use the lock within an
// "using" block.
using (var myLock = await asyncLock.GetReadLockAsync())
{
// Use Task.Delay to simulate asynchronous work, which means a different thread
// might continue execution after this point.
await Task.Delay(200);
}
}
Enter the lock in write mode in a synchronous method, using a timeout:
private void TestWriteMode(AsyncReaderWriterLockSlim asyncLock)
{
// Try to enter the lock within 2 seconds.
if (asyncLock.TryEnterWriteLock(2000))
{
try
{
// Simulate some work...
Thread.Sleep(200);
}
finally
{
asyncLock.ExitWriteLock();
}
}
else
{
// We could not enter the lock within the timeout...
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages (6)
Showing the top 5 NuGet packages that depend on AsyncReaderWriterLockSlim:
Package | Downloads |
---|---|
GoreRemoting
Grpc Remoting library for migration from .NET Remoting |
|
GoreRemoting.Serialization.BinaryFormatter
Grpc Remoting library for migration from .NET Remoting |
|
GoreRemoting.Serialization.Json
Grpc Remoting library for migration from .NET Remoting |
|
GoreRemoting.Serialization.MemoryPack
Grpc Remoting library for migration from .NET Remoting |
|
GoreRemoting.Serialization.MessagePack
Grpc Remoting library for migration from .NET Remoting |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 8,624 | 4/4/2024 |