Ejemplo n.º 1
0
        protected async Task WaitForIdleAsync(IExpeditableDelaySource expeditableDelaySource)
        {
            while (true)
            {
                if (CancellationToken.IsCancellationRequested)
                {
                    return;
                }

                var diffInMS = Environment.TickCount - _lastAccessTimeInMS;
                if (diffInMS >= BackOffTimeSpanInMS)
                {
                    return;
                }

                // TODO: will safestart/unwarp capture cancellation exception?
                var timeLeft = BackOffTimeSpanInMS - diffInMS;
                if (!await expeditableDelaySource.Delay(TimeSpan.FromMilliseconds(Math.Max(MinimumDelayInMS, timeLeft)), CancellationToken).ConfigureAwait(false))
                {
                    // The delay terminated early to accommodate a blocking operation. Make sure to delay long
                    // enough that low priority (on idle) operations get a chance to be triggered.
                    //
                    // 📝 At the time this was discovered, it was not clear exactly why the delay was needed in order
                    // to avoid live-lock scenarios.
                    await Task.Delay(TimeSpan.FromMilliseconds(10), CancellationToken).ConfigureAwait(false);

                    return;
                }
            }
        }
Ejemplo n.º 2
0
        protected async Task WaitForIdleAsync(IExpeditableDelaySource expeditableDelaySource)
        {
            while (true)
            {
                if (CancellationToken.IsCancellationRequested)
                {
                    return;
                }

                var diff = _timeSinceLastAccess.Elapsed;
                if (diff >= BackOffTimeSpan)
                {
                    return;
                }

                // TODO: will safestart/unwarp capture cancellation exception?
                var timeLeft = BackOffTimeSpan - diff;
                if (!await expeditableDelaySource.Delay(TimeSpan.FromMilliseconds(Math.Max(s_minimumDelay.TotalMilliseconds, timeLeft.TotalMilliseconds)), CancellationToken).ConfigureAwait(false))
                {
                    // The delay terminated early to accommodate a blocking operation. Make sure to yield so low
                    // priority (on idle) operations get a chance to be triggered.
                    //
                    // 📝 At the time this was discovered, it was not clear exactly why the yield (previously delay)
                    // was needed in order to avoid live-lock scenarios.
                    await Task.Yield().ConfigureAwait(false);

                    return;
                }
            }
        }
 public void EnqueueWork(
     Func <Task> workAsync,
     TaggerDelay delay,
     IExpeditableDelaySource delaySource,
     IAsyncToken asyncToken,
     CancellationToken cancellationToken)
 {
     lock (this)
     {
         _eventWorkQueue = _eventWorkQueue.ContinueWithAfterDelayFromAsync(
             _ => workAsync(),
             cancellationToken,
             delay.ComputeTimeDelay(),
             delaySource,
             TaskContinuationOptions.None,
             TaskScheduler.Default).CompletesAsyncOperation(asyncToken);
     }
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Create a ResettableDelay that will complete a task after a certain duration.  The delay
        /// can be reset at any point before it elapses in which case completion is postponed.  The
        /// delay can be reset multiple times.
        /// </summary>
        /// <param name="delayInMilliseconds">The time to delay before completing the task</param>
        /// <param name="foregroundTaskScheduler">Optional.  If used, the delay won't start until the supplied TaskScheduler schedules the delay to begin.</param>
        public ResettableDelay(int delayInMilliseconds, IExpeditableDelaySource expeditableDelaySource, TaskScheduler foregroundTaskScheduler = null)
        {
            Contract.ThrowIfFalse(delayInMilliseconds >= 50, "Perf, only use delays >= 50ms");
            _delayInMilliseconds    = delayInMilliseconds;
            _expeditableDelaySource = expeditableDelaySource;

            _taskCompletionSource = new TaskCompletionSource <object>();
            Reset();

            if (foregroundTaskScheduler != null)
            {
                Task.Factory.SafeStartNew(() => StartTimerAsync(continueOnCapturedContext: true), CancellationToken.None, foregroundTaskScheduler);
            }
            else
            {
                _ = StartTimerAsync(continueOnCapturedContext: false);
            }
        }