private static async Task ZAwaitAll(cMethodControl pMC, IEnumerable <Task> pTasks) { List <Task> lTasks = new List <Task>(); foreach (var lTask in pTasks) { if (lTask != null) { lTasks.Add(lTask); } } if (lTasks.Count == 0) { return; } using (var lAwaiter = new cAwaiter(pMC)) { Task lCompleted = await Task.WhenAny(lAwaiter.mTask, Task.WhenAll(lTasks)).ConfigureAwait(false); if (ReferenceEquals(lCompleted, lAwaiter.mTask)) { if (lAwaiter.mTask.IsCanceled) { throw new OperationCanceledException(); } throw new TimeoutException(); } List <Exception> lExceptions = new List <Exception>(); foreach (var lTask in lTasks) { if (lTask.Exception != null) { lExceptions.AddRange(lTask.Exception.Flatten().InnerExceptions); } else if (lTask.IsCanceled) { lExceptions.Add(new OperationCanceledException()); } } if (lExceptions.Count == 0) { return; } if (lExceptions.Count == 1) { throw lExceptions[0]; } throw new AggregateException(lExceptions); } }
/// <summary> /// Gets a disposable object that represents a block on the granting of exclusive access. /// This method will not complete until the block is issued or it throws due to <see cref="cMethodControl"/>. /// Dispose the returned object to release the block. /// </summary> /// <param name="pMC">Controls the execution of the method.</param> /// <param name="pParentContext">Context for trace messages.</param> /// <returns></returns> public async Task <cBlock> GetBlockAsync(cMethodControl pMC, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cExclusiveAccess), nameof(GetBlockAsync), mName, mInstance); if (mDisposed) { throw new ObjectDisposedException(nameof(cExclusiveAccess)); } if (!await mExclusiveSemaphoreSlim.WaitAsync(pMC.Timeout, pMC.CancellationToken).ConfigureAwait(false)) { throw new TimeoutException(); } Interlocked.Increment(ref mBlocks); mExclusiveSemaphoreSlim.Release(); return(new cBlock(mName, mSequence, mInstance, ZReleaseBlock, pParentContext)); }
/// <summary> /// Gets a disposable object that represents a grant of exclusive access. /// This method will not complete until the exclusive access is granted or it throws due to <see cref="cMethodControl"/>. /// Dispose the object to release the exclusive access. /// </summary> /// <param name="pMC">Controls the execution of the method.</param> /// <param name="pParentContext">Context for trace messages.</param> /// <returns></returns> public async Task <cToken> GetTokenAsync(cMethodControl pMC, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cExclusiveAccess), nameof(GetTokenAsync), mName, mInstance); if (mDisposed) { throw new ObjectDisposedException(nameof(cExclusiveAccess)); } if (!await mExclusiveSemaphoreSlim.WaitAsync(pMC.Timeout, pMC.CancellationToken).ConfigureAwait(false)) { throw new TimeoutException(); } while (mBlocks > 0) { if (!await mBlockCheckSemaphoreSlim.WaitAsync(pMC.Timeout, pMC.CancellationToken).ConfigureAwait(false)) { throw new TimeoutException(); } } mToken = new cToken(mName, mSequence, mInstance, ZReleaseToken, pParentContext); return(mToken); }
/// <summary> /// Initialises a new instance with the specified method control. /// </summary> /// <param name="pMC"></param> /// <remarks>If a timeout is specified then it runs from when the instance is created.</remarks> public cAwaiter(cMethodControl pMC) { mLinkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(mDisposeCancellationTokenSource.Token, pMC.CancellationToken); mTask = Task.Delay(pMC.Timeout, mLinkedCancellationTokenSource.Token); }
/// <inheritdoc cref="AwaitAll(cMethodControl, Task[])"/> public static Task AwaitAll(cMethodControl pMC, IEnumerable <Task> pTasks) => ZAwaitAll(pMC, pTasks);
/// <summary> /// Returns a task that completes when all of the passed tasks complete OR when the <see cref="cMethodControl"/> indicates timeout or cancellation. /// </summary> /// <param name="pMC"></param> /// <param name="pTasks">The set of tasks to wait for. Tasks in the set can be <see langword="null"/>.</param> /// <returns></returns> /// <remarks> /// If any of the passed tasks fail (times-out, was cancelled, or throws) then this method throws. /// If the <see cref="cMethodControl"/> indicates timeout or cancellation before all the tasks complete then this method throws. /// </remarks> public static Task AwaitAll(cMethodControl pMC, params Task[] pTasks) => ZAwaitAll(pMC, pTasks);