diff --git a/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs b/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs index eb8747b6..dfcf9fba 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs +++ b/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs @@ -23,7 +23,6 @@ public enum ThrottledActionMode public class ThrottledAction { private readonly TaskScheduler taskScheduler; - private readonly object cancellationTokenSourceLock = new object(); private readonly Action action; private readonly ThrottledActionMode mode; private readonly TimeSpan delayTime; @@ -44,50 +43,42 @@ public ThrottledAction(Action action) /// The argument action must not be null. public ThrottledAction(Action action, ThrottledActionMode mode, TimeSpan delayTime) { - taskScheduler = SynchronizationContext.Current != null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default; + taskScheduler = SynchronizationContext.Current is not null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default; this.action = action ?? throw new ArgumentNullException(nameof(action)); this.mode = mode; this.delayTime = delayTime; } /// Indicates that an execution of the action delegate is requested. - public bool IsRunning => cancellationTokenSource != null; + public bool IsRunning => cancellationTokenSource is not null; /// Requests the execution of the action delegate. public void InvokeAccumulated() { - CancellationToken? token = null; - lock (cancellationTokenSourceLock) - { - if (mode == ThrottledActionMode.InvokeOnlyIfIdleForDelayTime || cancellationTokenSource == null) - { - cancellationTokenSource?.Cancel(); - cancellationTokenSource = new CancellationTokenSource(); - token = cancellationTokenSource.Token; - } - } + if (mode is not ThrottledActionMode.InvokeOnlyIfIdleForDelayTime && cancellationTokenSource is not null) return; - if (token != null) + var cts = new CancellationTokenSource(); + if (mode is ThrottledActionMode.InvokeOnlyIfIdleForDelayTime) + { + Interlocked.Exchange(ref cancellationTokenSource, cts)?.Cancel(); + } + else // mode is InvokeMaxEveryDelayTime { - Task.Delay(delayTime, token.Value).ContinueWith(t => - { - lock (cancellationTokenSourceLock) - { - cancellationTokenSource = null; - } - TaskHelper.Run(action, taskScheduler); - }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); + var old = Interlocked.CompareExchange(ref cancellationTokenSource, cts, null); + if (old is not null) return; } + + Task.Delay(delayTime, cts.Token).ContinueWith(t => + { + Interlocked.Exchange(ref cancellationTokenSource, null); + TaskHelper.Run(action, taskScheduler); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); } /// Cancel the execution of the action delegate that was requested. public void Cancel() { - lock (cancellationTokenSourceLock) - { - cancellationTokenSource?.Cancel(); - cancellationTokenSource = null; - } + Interlocked.Exchange(ref cancellationTokenSource, null)?.Cancel(); } } }