What's the best way to sleep a certain amount of time, but be able to be interrupted by a IsCancellationRequested
from a CancellationToken
?
I'm looking for a solution which works in .NET 4.0.
I'd like to write
void MyFunc (CancellationToken ct)
{
//...
// simulate some long lasting operation that should be cancelable
Thread.Sleep(TimeSpan.FromMilliseconds(10000), ct);
}
Introduction to C# WaitC # wait is defined as waits for the task to finish its execution. It sources the current thread to wait until another thread calls its notify() or notifyAll() methods.
Delay() Function This function is present in the “Systems Threading Tasks” namespace, so that this function will be used with the “Task” keyword. The Delay() function has the parameter, an integer variable that specifies the time for a task to be stopped and processes values in milliseconds.
When given a CancellationToken , you can create a new instance of the token source, assign it's token to the provided token, and cancel it. All other parties that can read this token will see that it's cancellation has been requested.
A CancellationTokenSource object, which provides a cancellation token through its Token property and sends a cancellation message by calling its Cancel or CancelAfter method. A CancellationToken object, which indicates whether cancellation is requested.
I just blogged about it here:
CancellationToken and Thread.Sleep
in Short:
var cancelled = token.WaitHandle.WaitOne(TimeSpan.FromSeconds(5));
In your context:
void MyFunc (CancellationToken ct)
{
//...
// simulate some long lasting operation that should be cancelable
var cancelled = ct.WaitHandle.WaitOne(TimeSpan.FromSeconds(10));
}
Alternatively, I think this is pretty clear:
Task.Delay(waitTimeInMs, cancellationToken).Wait(cancellationToken);
To cancel an asynchronious operation after a certain amount of time whilst still being able to cancel the operation manually use something like the following
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
cts.CancelAfter(5000);
This will cause a cancellation after five seconds. To cancel the operation your self all you have to do is pass the token
into your async method and use the token.ThrowifCancellationRequested()
method, where you have set up an event handler somewhere to fire cts.Cancel()
.
So a full example is:
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
cts.CancelAfter(5000);
// Set up the event handler on some button.
if (cancelSource != null)
{
cancelHandler = delegate
{
Cancel(cts);
};
stopButton.Click -= cancelHandler;
stopButton.Click += cancelHandler;
}
// Now launch the method.
SomeMethodAsync(token);
Where stopButton
is the button you click to cancel the running task
private void Cancel(CancellationTokenSource cts)
{
cts.Cancel();
}
and the method is defined as
SomeMethodAsync(CancellationToken token)
{
Task t = Task.Factory.StartNew(() =>
{
msTimeout = 5000;
Pump(token);
}, token,
TaskCreationOptions.None,
TaskScheduler.Default);
}
Now, to enable you to work the thread but also enable user cancellation, you will need to write a 'pumping' method
int msTimeout;
bool timeLimitReached = false;
private void Pump(CancellationToken token)
{
DateTime now = DateTime.Now;
System.Timer t = new System.Timer(100);
t.Elapsed -= t_Elapsed;
t.Elapsed += t_Elapsed;
t.Start();
while(!timeLimitReached)
{
Thread.Sleep(250);
token.ThrowIfCancellationRequested();
}
}
void t_Elapsed(object sender, ElapsedEventArgs e)
{
TimeSpan elapsed = DateTime.Now - this.readyUpInitialised;
if (elapsed > msTimeout)
{
timeLimitReached = true;
t.Stop();
t.Dispose();
}
}
Note, SomeAsyncMethod
will return right to the caller. To block the caller aswell you will have to move the Task
up in the call hierarchy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With