Table of Contents

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 JoinableTaskContext

A 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 bool

true 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 bool

true 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

AsyncReaderWriterLock.LockHandle

CanCurrentThreadHoldActiveLock

Gets a value indicating whether the current thread is allowed to hold an active lock.

protected virtual bool CanCurrentThreadHoldActiveLock { get; }

Property Value

bool

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

bool

Completion

Gets a task whose completion signals that this lock will no longer issue locks.

public Task Completion { get; }

Property Value

Task

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

TimeSpan

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

bool

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

bool

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

bool

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

bool

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

bool

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

bool

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

bool

IsUpgradeableReadLockHeld

Gets a value indicating whether the caller holds an upgradeable read lock.

public bool IsUpgradeableReadLockHeld { get; }

Property Value

bool

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

bool

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

SynchronizationContext

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

object

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

disposing bool

true if Dispose() was called; false if the object is being finalized.

GetAggregateLockFlags()

Returns the aggregate of the lock flags for all nested locks.

protected AsyncReaderWriterLock.LockFlags GetAggregateLockFlags()

Returns

AsyncReaderWriterLock.LockFlags

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.LockFlags

The flag(s) that must be specified for a true result.

handle AsyncReaderWriterLock.LockHandle

The head of the lock stack to consider.

Returns

bool

true if all the specified flags are found somewhere in the lock stack; false otherwise.

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 bool

true if the last write lock that the caller holds is being released; false otherwise.

releasingLock AsyncReaderWriterLock.LockHandle

The 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 Exception

The 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 string

The 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

Task

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 CancellationToken

A 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.LockFlags

Modifications to normal lock behavior.

cancellationToken CancellationToken

A 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 CancellationToken

A 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.LockFlags

Modifications to normal lock behavior.

cancellationToken CancellationToken

A 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 CancellationToken

A 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.