public async Task AsyncLock_CancelledLock_LeavesLockUnlocked() { AsyncLock mutex = new AsyncLock(); CancellationTokenSource cts = new CancellationTokenSource(); TaskCompletionSource <object> taskReady = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); IDisposable unlock = await mutex.LockAsync(); Task task = Task.Run(async() => { AwaitableDisposable <IDisposable> lockTask = mutex.LockAsync(cts.Token); taskReady.SetResult(null); await lockTask; }); await taskReady.Task; cts.Cancel(); await AsyncAssert.ThrowsAsync <OperationCanceledException>(task).ConfigureAwait(false); Assert.True(task.IsCanceled); unlock.Dispose(); AwaitableDisposable <IDisposable> finalLockTask = mutex.LockAsync(); await finalLockTask; }
public async Task Unlocked_PermitsLock() { AsyncMonitor monitor = new AsyncMonitor(); AwaitableDisposable <IDisposable> task = monitor.EnterAsync(); await task; }
public void AsyncLock_PreCancelled_Locked_SynchronouslyCancels() { AsyncLock mutex = new AsyncLock(); AwaitableDisposable <IDisposable> lockTask = mutex.LockAsync(); CancellationToken token = new CancellationToken(true); Task <IDisposable> task = mutex.LockAsync(token).AsTask(); Assert.True(task.IsCompleted); Assert.True(task.IsCanceled); Assert.False(task.IsFaulted); }
/// <summary> /// Start the next available G/M/T-code and wait until this code may finish /// </summary> /// <returns>Awaitable disposable</returns> private AwaitableDisposable <IDisposable> WaitForFinish() { if (!Flags.HasFlag(CodeFlags.Unbuffered)) { StartNextCode(); } if (Interception.IsInterceptingConnection(SourceConnection)) { return(new AwaitableDisposable <IDisposable>(Task.FromResult <IDisposable>(null))); } AwaitableDisposable <IDisposable> finishTask = (Macro == null) ? _codeFinishLocks[(int)Channel, (int)_codeType].LockAsync(CancellationToken) : Macro.WaitForCodeFinish(); return(finishTask); }
public async Task PulseAll_ReleasesAllWaiters() { AsyncMonitor monitor = new AsyncMonitor(); int[] completed = { 0 }; TaskCompletionSource <object> task1Ready = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); TaskCompletionSource <object> task2Ready = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); Task waitTask1 = null; Task task1 = Task.Run(async() => { using (await monitor.EnterAsync()) { waitTask1 = monitor.WaitAsync(); task1Ready.SetResult(null); await waitTask1; Interlocked.Increment(ref completed[0]); } }); await task1Ready.Task; Task waitTask2 = null; Task task2 = Task.Run(async() => { using (await monitor.EnterAsync()) { waitTask2 = monitor.WaitAsync(); task2Ready.SetResult(null); await waitTask2; Interlocked.Increment(ref completed[0]); } }); await task2Ready.Task; AwaitableDisposable <IDisposable> lockTask3 = monitor.EnterAsync(); using (await lockTask3) { monitor.PulseAll(); } await Task.WhenAll(task1, task2).ConfigureAwait(false); int result = Interlocked.CompareExchange(ref completed[0], 0, 0); Assert.Equal(2, result); }
public async Task AsyncLock_Locked_OnlyPermitsOneLockerAtATime() { AsyncLock mutex = new AsyncLock(); TaskCompletionSource <object> task1HasLock = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); TaskCompletionSource <object> task1Continue = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); TaskCompletionSource <object> task2Ready = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); TaskCompletionSource <object> task2HasLock = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); TaskCompletionSource <object> task2Continue = TaskCompletionSourceExtensions.CreateAsyncTaskSource <object>(); Task task1 = Task.Run(async() => { using (await mutex.LockAsync()) { task1HasLock.SetResult(null); await task1Continue.Task; } }); await task1HasLock.Task; Task task2 = Task.Run(async() => { AwaitableDisposable <IDisposable> key = mutex.LockAsync(); task2Ready.SetResult(null); using (await key) { task2HasLock.SetResult(null); await task2Continue.Task; } }); await task2Ready.Task; Task task3 = Task.Run(async() => await mutex.LockAsync()); task1Continue.SetResult(null); await task2HasLock.Task; Assert.False(task3.IsCompleted); task2Continue.SetResult(null); await task2; await task3; }
public static ConfiguredTaskAwaitable <TResult> AnyContext <TResult>(this AwaitableDisposable <TResult> task) where TResult : IDisposable { return(task.ConfigureAwait(continueOnCapturedContext: false)); }
/// <summary> /// Configures the await to not attempt to marshal the continuation back to the original context captured. /// </summary> /// <typeparam name="T">The type of the result of the underlying task.</typeparam> /// <param name="awaitable">The awaitable to configure the await for.</param> /// <returns> /// An object used to await this awaitable. /// </returns> /// <remarks> /// This method makes it so that the code after the await can be ran on any available thread pool thread /// instead of being marshalled back to the same thread that the code was running on before the await. /// Avoiding this marshalling helps to slightly improve performance and helps avoid potential deadlocks. See /// <see href="http://blog.ciber.no/2014/05/19/using-task-configureawaitfalse-to-prevent-deadlocks-in-async-code/"> /// this link</see> for more information. /// </remarks> public static ConfiguredTaskAwaitable <T> DontMarshallContext <T>(this AwaitableDisposable <T> awaitable) where T : IDisposable => awaitable.ConfigureAwait(false);