Class AsyncReaderWriterLock
- Namespace
- Microsoft.VisualStudio.Threading
- Assembly
- Microsoft.VisualStudio.Threading.dll
A non-blocking lock that allows concurrent access, exclusive access, or concurrent with upgradeability to exclusive access.
public class AsyncReaderWriterLock : IHangReportContributor, IDisposable
- Inheritance
-
AsyncReaderWriterLock
- Implements
- Derived
- Inherited Members
Remarks
We have to use a custom awaitable rather than simply returning Task{LockReleaser} because we have to set CallContext data in the context of the person receiving the lock, which requires that we get to execute code at the start of the continuation (whether we yield or not).
Constructors
AsyncReaderWriterLock()
Initializes a new instance of the AsyncReaderWriterLock class.
public AsyncReaderWriterLock()
AsyncReaderWriterLock(JoinableTaskContext?, bool)
Initializes a new instance of the AsyncReaderWriterLock class.
public AsyncReaderWriterLock(JoinableTaskContext? joinableTaskContext, bool captureDiagnostics = false)
Parameters
joinableTaskContext
JoinableTaskContextA JoinableTaskContext to help resolve deadlocks caused by interdependency between top read lock tasks when there is a pending write lock blocking one of them.
captureDiagnostics
booltrue to spend additional resources capturing diagnostic details that can be used to analyze deadlocks or other issues.
AsyncReaderWriterLock(bool)
Initializes a new instance of the AsyncReaderWriterLock class.
public AsyncReaderWriterLock(bool captureDiagnostics)
Parameters
captureDiagnostics
booltrue to spend additional resources capturing diagnostic details that can be used to analyze deadlocks or other issues.
Properties
AmbientLock
Gets the lock held by the caller's execution context.
protected AsyncReaderWriterLock.LockHandle AmbientLock { get; }
Property Value
CanCurrentThreadHoldActiveLock
Gets a value indicating whether the current thread is allowed to hold an active lock.
protected virtual bool CanCurrentThreadHoldActiveLock { get; }
Property Value
Remarks
The default implementation of this property returns true when the calling thread is NOT an STA thread. This property may be overridden to return false on threads that may compromise the integrity of the lock.
CaptureDiagnostics
Gets or sets a value indicating whether additional resources should be spent to collect information that would be useful in diagnosing deadlocks, etc.
protected bool CaptureDiagnostics { get; set; }
Property Value
Completion
Gets a task whose completion signals that this lock will no longer issue locks.
public Task Completion { get; }
Property Value
Remarks
This task only transitions to a complete state after a call to Complete().
DeadlockCheckTimeout
Gets a time delay to check whether pending writer lock and reader locks forms a deadlock.
protected virtual TimeSpan DeadlockCheckTimeout { get; }
Property Value
IsAnyLockHeld
Gets a value indicating whether any kind of lock is held by the caller and can be immediately used given the caller's context.
public bool IsAnyLockHeld { get; }
Property Value
IsAnyPassiveLockHeld
Gets a value indicating whether any kind of lock is held by the caller without regard to the lock compatibility of the caller's context.
public bool IsAnyPassiveLockHeld { get; }
Property Value
IsPassiveReadLockHeld
Gets a value indicating whether a read lock is held by the caller without regard to the lock compatibility of the caller's context.
public bool IsPassiveReadLockHeld { get; }
Property Value
Remarks
This property returns false if any other lock type is held, unless within that alternate lock type this lock is also nested.
IsPassiveUpgradeableReadLockHeld
Gets a value indicating whether an upgradeable read lock is held by the caller without regard to the lock compatibility of the caller's context.
public bool IsPassiveUpgradeableReadLockHeld { get; }
Property Value
Remarks
This property returns false if any other lock type is held, unless within that alternate lock type this lock is also nested.
IsPassiveWriteLockHeld
Gets a value indicating whether a write lock is held by the caller without regard to the lock compatibility of the caller's context.
public bool IsPassiveWriteLockHeld { get; }
Property Value
Remarks
This property returns false if any other lock type is held, unless within that alternate lock type this lock is also nested.
IsReadLockHeld
Gets a value indicating whether the caller holds a read lock.
public bool IsReadLockHeld { get; }
Property Value
Remarks
This property returns false if any other lock type is held, unless within that alternate lock type this lock is also nested.
IsUnsupportedSynchronizationContext
Gets a value indicating whether the current SynchronizationContext is one that is not supported by this lock.
protected virtual bool IsUnsupportedSynchronizationContext { get; }
Property Value
IsUpgradeableReadLockHeld
Gets a value indicating whether the caller holds an upgradeable read lock.
public bool IsUpgradeableReadLockHeld { get; }
Property Value
Remarks
This property returns false if any other lock type is held, unless within that alternate lock type this lock is also nested.
IsWriteLockHeld
Gets a value indicating whether the caller holds a write lock.
public bool IsWriteLockHeld { get; }
Property Value
Remarks
This property returns false if any other lock type is held, unless within that alternate lock type this lock is also nested.
NoMessagePumpSynchronizationContext
Gets a SynchronizationContext which, when applied, suppresses any message pump that may run during synchronous blocks of the calling thread.
protected virtual SynchronizationContext NoMessagePumpSynchronizationContext { get; }
Property Value
Remarks
The default implementation of this property is effective in builds of this assembly that target the .NET Framework. But on builds that target the portable profile, it should be overridden to provide an effective platform-specific solution.
SyncObject
Gets the object used to synchronize access to this instance's fields.
protected object SyncObject { get; }
Property Value
Methods
Complete()
Causes new top-level lock requests to be rejected and the Completion task to transition to a completed state after any issued locks have been released.
public void Complete()
Dispose()
public void Dispose()
Dispose(bool)
Disposes managed and unmanaged resources held by this instance.
protected virtual void Dispose(bool disposing)
Parameters
GetAggregateLockFlags()
Returns the aggregate of the lock flags for all nested locks.
protected AsyncReaderWriterLock.LockFlags GetAggregateLockFlags()
Returns
Remarks
This is not redundant with LockStackContains(LockFlags, LockHandle) because that returns fast once the presence of certain flag(s) is determined, whereas this will aggregate all flags, some of which may be defined by derived types.
GetHangReport()
Contributes data for a hang report.
protected virtual HangReportContribution GetHangReport()
Returns
- HangReportContribution
The hang report contribution. Null values should be ignored.
GetTaskSchedulerForReadLockRequest()
Get the task scheduler to execute the continuation when the lock is acquired. AsyncReaderWriterLock uses a special SynchronizationContext to handle exclusive locks, and will ignore task scheduler provided, so this is only used in a read lock scenario. This method is called within the execution context to wait the read lock, so it can pick up TaskScheduler based on the current execution context. Note: the task scheduler is only used, when the lock is issued later. If the lock is issued immediately when CanCurrentThreadHoldActiveLock returns true, it will be ignored.
protected virtual TaskScheduler GetTaskSchedulerForReadLockRequest()
Returns
- TaskScheduler
A task scheduler to schedule the continuation task when a lock is issued.
HideLocks()
Prevents use or visibility of the caller's lock(s) until the returned value is disposed.
public AsyncReaderWriterLock.Suppression HideLocks()
Returns
- AsyncReaderWriterLock.Suppression
The value to dispose to restore lock visibility.
Remarks
This can be used by a write lock holder that is about to fork execution to avoid two threads simultaneously believing they hold the exclusive write lock. The lock should be hidden just before kicking off the work and can be restored immediately after kicking off the work.
LockStackContains(LockFlags, LockHandle)
Checks whether the aggregated flags from all locks in the lock stack satisfy the specified flag(s).
protected bool LockStackContains(AsyncReaderWriterLock.LockFlags flags, AsyncReaderWriterLock.LockHandle handle)
Parameters
flags
AsyncReaderWriterLock.LockFlagsThe flag(s) that must be specified for a true result.
handle
AsyncReaderWriterLock.LockHandleThe head of the lock stack to consider.
Returns
OnBeforeExclusiveLockReleasedAsync()
Fired when the last write lock is about to be released.
protected virtual Task OnBeforeExclusiveLockReleasedAsync()
Returns
- Task
A task whose completion signals the conclusion of the asynchronous operation.
OnBeforeLockReleasedAsync(bool, LockHandle)
Fired when any lock is being released.
protected virtual Task OnBeforeLockReleasedAsync(bool exclusiveLockRelease, AsyncReaderWriterLock.LockHandle releasingLock)
Parameters
exclusiveLockRelease
booltrue if the last write lock that the caller holds is being released; false otherwise.
releasingLock
AsyncReaderWriterLock.LockHandleThe lock being released.
Returns
- Task
A task whose completion signals the conclusion of the asynchronous operation.
OnBeforeWriteLockReleased(Func<Task>)
Registers a callback to be invoked when the write lock held by the caller is about to be ultimately released (outermost write lock).
public void OnBeforeWriteLockReleased(Func<Task> action)
Parameters
action
Func<Task>The asynchronous delegate to invoke. Access to the write lock is provided throughout the asynchronous invocation.
Remarks
This supports some scenarios VC++ has where change event handlers need to inspect changes, or follow up with other changes to respond to earlier changes, at the conclusion of the lock. This method is safe to call from within a previously registered callback, in which case the registered callback will run when previously registered callbacks have completed execution. If the write lock is released to an upgradeable read lock, these callbacks are fired synchronously with respect to the writer who is releasing the lock. Otherwise, the callbacks are invoked asynchronously with respect to the releasing thread.
OnCriticalFailure(Exception)
Invoked when the lock detects an internal error or illegal usage pattern that indicates a serious flaw that should be immediately reported to the application and/or bring down the process to avoid hangs or data corruption.
protected virtual Exception OnCriticalFailure(Exception ex)
Parameters
ex
ExceptionThe exception that captures the details of the failure.
Returns
- Exception
An exception that may be returned by some implementations of tis method for he caller to rethrow.
OnCriticalFailure(string)
Invoked when the lock detects an internal error or illegal usage pattern that indicates a serious flaw that should be immediately reported to the application and/or bring down the process to avoid hangs or data corruption.
protected Exception OnCriticalFailure(string message)
Parameters
message
stringThe message to use for the exception.
Returns
- Exception
An exception that may be returned by some implementations of tis method for he caller to rethrow.
OnExclusiveLockReleasedAsync()
Invoked after an exclusive lock is released but before anyone has a chance to enter the lock.
protected virtual Task OnExclusiveLockReleasedAsync()
Returns
Remarks
This method is called while holding a private lock in order to block future lock consumers till this method is finished.
OnUpgradeableReadLockReleased()
Invoked when a top-level upgradeable read lock is released, leaving no remaining (write) lock.
protected virtual void OnUpgradeableReadLockReleased()
ReadLockAsync(CancellationToken)
Obtains a read lock, asynchronously awaiting for the lock if it is not immediately available.
public AsyncReaderWriterLock.Awaitable ReadLockAsync(CancellationToken cancellationToken = default)
Parameters
cancellationToken
CancellationTokenA token whose cancellation indicates lost interest in obtaining the lock. A canceled token does not release a lock that has already been issued. But if the lock isn't immediately available, a canceled token will cause the code that is waiting for the lock to resume with an OperationCanceledException.
Returns
- AsyncReaderWriterLock.Awaitable
An awaitable object whose result is the lock releaser.
Exceptions
- InvalidOperationException
Thrown when Complete() has been called and this is a new top-level lock request.
UpgradeableReadLockAsync(LockFlags, CancellationToken)
Obtains an upgradeable read lock, asynchronously awaiting for the lock if it is not immediately available.
public AsyncReaderWriterLock.Awaitable UpgradeableReadLockAsync(AsyncReaderWriterLock.LockFlags options, CancellationToken cancellationToken = default)
Parameters
options
AsyncReaderWriterLock.LockFlagsModifications to normal lock behavior.
cancellationToken
CancellationTokenA token whose cancellation indicates lost interest in obtaining the lock. A canceled token does not release a lock that has already been issued. But if the lock isn't immediately available, a canceled token will cause the code that is waiting for the lock to resume with an OperationCanceledException.
Returns
- AsyncReaderWriterLock.Awaitable
An awaitable object whose result is the lock releaser.
Exceptions
- InvalidOperationException
Thrown when Complete() has been called and this is a new top-level lock request.
UpgradeableReadLockAsync(CancellationToken)
Obtains an upgradeable read lock, asynchronously awaiting for the lock if it is not immediately available.
public AsyncReaderWriterLock.Awaitable UpgradeableReadLockAsync(CancellationToken cancellationToken = default)
Parameters
cancellationToken
CancellationTokenA token whose cancellation indicates lost interest in obtaining the lock. A canceled token does not release a lock that has already been issued. But if the lock isn't immediately available, a canceled token will cause the code that is waiting for the lock to resume with an OperationCanceledException.
Returns
- AsyncReaderWriterLock.Awaitable
An awaitable object whose result is the lock releaser.
Exceptions
- InvalidOperationException
Thrown when Complete() has been called and this is a new top-level lock request.
WriteLockAsync(LockFlags, CancellationToken)
Obtains a write lock, asynchronously awaiting for the lock if it is not immediately available.
public AsyncReaderWriterLock.Awaitable WriteLockAsync(AsyncReaderWriterLock.LockFlags options, CancellationToken cancellationToken = default)
Parameters
options
AsyncReaderWriterLock.LockFlagsModifications to normal lock behavior.
cancellationToken
CancellationTokenA token whose cancellation indicates lost interest in obtaining the lock. A canceled token does not release a lock that has already been issued. But if the lock isn't immediately available, a canceled token will cause the code that is waiting for the lock to resume with an OperationCanceledException.
Returns
- AsyncReaderWriterLock.Awaitable
An awaitable object whose result is the lock releaser.
Exceptions
- InvalidOperationException
Thrown when Complete() has been called and this is a new top-level lock request.
WriteLockAsync(CancellationToken)
Obtains a write lock, asynchronously awaiting for the lock if it is not immediately available.
public AsyncReaderWriterLock.Awaitable WriteLockAsync(CancellationToken cancellationToken = default)
Parameters
cancellationToken
CancellationTokenA token whose cancellation indicates lost interest in obtaining the lock. A canceled token does not release a lock that has already been issued. But if the lock isn't immediately available, a canceled token will cause the code that is waiting for the lock to resume with an OperationCanceledException.
Returns
- AsyncReaderWriterLock.Awaitable
An awaitable object whose result is the lock releaser.
Exceptions
- InvalidOperationException
Thrown when Complete() has been called and this is a new top-level lock request.