public async ValueTask <IDisposable?> TryAcquireAsync(TimeoutValue timeout, CancellationToken cancellationToken) { var acquired = SyncViaAsync.IsSynchronous ? this._semaphore.Wait(timeout.InMilliseconds, cancellationToken) : await this._semaphore.WaitAsync(timeout.InMilliseconds, cancellationToken).ConfigureAwait(false); return(acquired ? new Handle(this._semaphore) : null); }
public static async ValueTask <TResult?> WaitAsync <TState, TResult>( TState state, Func <TState, CancellationToken, ValueTask <TResult?> > tryGetValue, TimeoutValue timeout, TimeoutValue minSleepTime, TimeoutValue maxSleepTime, CancellationToken cancellationToken) where TResult : class { Invariant.Require(minSleepTime.CompareTo(maxSleepTime) <= 0); Invariant.Require(!maxSleepTime.IsInfinite); var initialResult = await tryGetValue(state, cancellationToken).ConfigureAwait(false); if (initialResult != null || timeout.IsZero) { return(initialResult); } using var _ = CreateMergedCancellationTokenSourceSource(timeout, cancellationToken, out var mergedCancellationToken); var random = new Random(Guid.NewGuid().GetHashCode()); var sleepRangeMillis = maxSleepTime.InMilliseconds - minSleepTime.InMilliseconds; while (true) { var sleepTime = minSleepTime.TimeSpan + TimeSpan.FromMilliseconds(random.NextDouble() * sleepRangeMillis); try { await SyncViaAsync.Delay(sleepTime, mergedCancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when(IsTimedOut()) { // if we time out while sleeping, always try one more time with just the regular token return(await tryGetValue(state, cancellationToken).ConfigureAwait(false)); } try { var result = await tryGetValue(state, mergedCancellationToken).ConfigureAwait(false); if (result != null) { return(result); } } catch (OperationCanceledException) when(IsTimedOut()) { return(null); } } bool IsTimedOut() => mergedCancellationToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested; }
/// <summary> /// A <see cref="SyncViaAsync"/>-compatible implementation of <see cref="Task.Delay(TimeSpan, CancellationToken)"/>. /// </summary> public static ValueTask Delay(TimeoutValue timeout, CancellationToken cancellationToken) { if (!IsSynchronous) { return(Task.Delay(timeout.InMilliseconds, cancellationToken).AsValueTask()); } if (cancellationToken.CanBeCanceled) { if (cancellationToken.WaitHandle.WaitOne(timeout.InMilliseconds)) { throw new OperationCanceledException("delay was canceled", cancellationToken); } } else { Thread.Sleep(timeout.InMilliseconds); } return(default);
private static IDisposable?CreateMergedCancellationTokenSourceSource(TimeoutValue timeout, CancellationToken cancellationToken, out CancellationToken mergedCancellationToken) { if (timeout.IsInfinite) { mergedCancellationToken = cancellationToken; return(null); } if (!cancellationToken.CanBeCanceled) { var timeoutSource = new CancellationTokenSource(millisecondsDelay: timeout.InMilliseconds); mergedCancellationToken = timeoutSource.Token; return(timeoutSource); } var mergedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); mergedSource.CancelAfter(timeout.InMilliseconds); mergedCancellationToken = mergedSource.Token; return(mergedSource); }
private static Task CreateMonitoringLoopTask(WeakReference <LeaseMonitor> weakMonitor, TimeoutValue monitoringCadence, CancellationToken disposalToken) { return(Task.Run(() => MonitoringLoop())); async Task MonitoringLoop() { var leaseLifetime = Stopwatch.StartNew(); do { // wait until the next monitoring check await Task.Delay(monitoringCadence.InMilliseconds, disposalToken).TryAwait(); }while (!disposalToken.IsCancellationRequested && await RunMonitoringLoopIterationAsync(weakMonitor, leaseLifetime).ConfigureAwait(false)); } }