There are several errors in your code that make things confusing.
First, you use Thread.Sleep instead of Task.Delay or some other timer-based method (I highly recommend writing your own if you don't have access to Task.Delay). Sleep is a blocking wait and cannot be caused by a cancellation token. The result is that the threads of the threads of the flow of precious objects are held hostage for several seconds, even if the operation is canceled. This may result in later button presses being supported earlier.
Secondly, at the end of the wait, you cancel _source, but this refers to the current value of the source, and not to the value at the time the button is clicked. Previous button presses will override subsequent button press effects instead of their own.
Thirdly, you delete the source of the cancellation token in one thread while you are chasing to cancel it on another. You are lucky that you do not get object-related exceptions.
Fourth, it would be ideal to use async in such a situation. You mentioned that you were only on .Net 4.0.
Fixing the first three things should do what is easier to reason about:
CancellationTokenSource _prevSource = new CancellationTokenSource(); public void OnButtonPress() { var curSource = new CancellationTokenSource(); _prevSource.Cancel(); _prevSource = curSource; MyCustomDelay(TimeSpan.FromSeconds(5), curSource.Token).ContinueWith(t => { curSource.Cancel(); }, TaskContinuationOptions.OnlyOnRanToCompletion); var r = MyCustomDelay(TimeSpan.FromSeconds(20), curSource.Token).ContinueWith(t => { curSource.ThrowIfCancellationRequested(); }, TaskContinuationOptions.OnlyOnRanToCompletion);
source share