Cancelling execution of a method called with await - c#

I'm trying to cancel the execution of the DoSomethingAsync method which I call using await.
When I click on the cancel button the execution is not cancelled and I don't see the "Execution was cancelled" message box, but instead I see the other message box.
I don't understand why it's not working. I am still learning this part of C# and I took this example at http://www.codeproject.com/Articles/127291/C-vNext-New-Asynchronous-Pattern#heading0015 (I simplified it).
public class MyClass : Class
{
CancellationTokenSource cts;
private async void searchButton_Click(object sender, EventArgs e)
{
await DoSomethingAsync();
}
private void cancelButton_Click(object sender, EventArgs e)
{
cts.Cancel();
}
async void DoSomethingAsync()
{
cts = new CancellationTokenSource();
try
{
await SuperSlowProcess();
MessageBox.Show("You will only see this if execution is not cancelled");
}
catch (TaskCanceledException)
{
MessageBox.Show("Execution was cancelled");
}
}
}

In order to make it working, you actually need to use CancellationToken in the SuperSlowProcess:
public Task SuperSlowProcess(CancellationToken cancellationToken)
{
return Task.Run(() => {
// you need to check cancellationToken periodically to check if cancellation has been requested
for (int i = 0; i < 10; i++)
{
cancellationToken.ThrowIfCancellationRequested(); // this will throw OperationCancelledException after CancellationTokenSource.Cancel() is called
Thread.Sleep(200); // to emulate super slow process
}
});
}
Of course, it depends on the implementation of SuperSlowProcess. If it's not possible to check CancellationToken periodically, you could check it only once - in the very end, something like that:
public async Task SuperSlowProcess2(CancellationToken cancellationToken)
{
var response = await CallExternalApi();
cancellationToken.ThrowIfCancellationRequested();
}
and then
async void DoSomethingAsync()
{
cts = new CancellationTokenSource();
try
{
await SuperSlowProcess(cts.Token);
MessageBox.Show("You will only see this if execution is not cancelled");
}
catch (OperationCanceledException) // Note that exception type is different
{
MessageBox.Show("Execution was cancelled");
}
}

Related

X second delay between two tasks c#

I want to delay 80 milliseconds between task 1 and task 2.
But here Task 1 and Task 2 run together.
my code:
private CancellationTokenSource cts = new CancellationTokenSource();
private async void button4_Click(object sender, EventArgs e)
{
//SendBuyOrder();
try
{
await Task.WhenAll(Task1(cts.Token), Task2(cts.Token));
//await Task.WhenAll(Task1(cts.Token));
}
catch (Exception ex)
{
}
}
public void send(int t)
{
txtResult.AppendText("Task" + t + ": " + DateTime.Now.ToString("hh:mm:ss.fff"));
txtResult.AppendText(Environment.NewLine);
txtResult.AppendText(Environment.NewLine);
}
public async Task Task1(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
await Task.Delay(Convert.ToInt32(txtRepeatInterval.Text), token);
send(1);
}
}
public async Task Task2(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
await Task.Delay(Convert.ToInt32(txtRepeatInterval.Text), token);
send(2);
}
}
Here, Task 1 and Task 2 are run together, and 80 milliseconds after Task 1 is run again. I want task 2 to be performed 80 milliseconds after starting task 1
enter image description here
You can make one task that does both:
public async Task Task3(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
await Task.Delay(Convert.ToInt32(txtRepeatInterval.Text), token);
send(1);
await Task.Delay(80, token);
send(2);
}
}

Basic threading with single backgroundworker for multiple tasks

I'd want to guarantee the order of execution in a single backgroundworker thread like this
One BackgroundWorker DoWork =
{
First();
Second();
Third();
...
}
Function First()
{
try{
X();
Y();
Z(); //etc
}catch
}
The question is marked for C#. Assuming the code is a representation of what you want to achieve in C# consider:
private void button1_Click(object sender, EventArgs e)
{
//If you need a return result
//Task.FromResult(MainThread().ConfigureAwait(false));
Task.Run(MainThread);
}
private async Task MainThread()
{
var result1 = await Task1().ConfigureAwait(false);
await Task2().ConfigureAwait(false);
var result3 = await Task3().ConfigureAwait(false);
}
private async Task<int> Task1()
{
await Task.Delay(2000).ConfigureAwait(false);
Debug.WriteLine("Executed task 1");
return 1;
}
private async Task Task2()
{
await Task.Delay(100).ConfigureAwait(false);
Debug.WriteLine("Executed task 2");
}
private async Task<int> Task3()
{
await Task.Delay(1000).ConfigureAwait(false);
Debug.WriteLine("Executed task 3");
return 3;
}

Long Running Action Timeout in .Net Core

How can I implement a timeout for a potentially long running action lambda? I have tried wrapping the action in a Task and then using a cancellation token to enforce the timeout but to no avail.
public void LongRunningTask()
{
ExecuteSafely(() => //do something );
}
private void ExecuteSafely(Action action)
{
try
{
action();
}
catch
{
// just don't crash
}
}
New implementation as per 1st answer:
public void Information<T>(string messageTemplate, T propertyValue)
{
ExecuteSafely(() => _logger.Information(messageTemplate, propertyValue));
}
private void ExecuteSafely(Action action)
{
try
{
var cts = new CancellationTokenSource();
cts.CancelAfter(new TimeSpan(0, 0, 1));
try
{
Task.Run(action, cts.Token).Wait();
}
catch (TaskCanceledException e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
//here you know the task is cancelled due to timeout
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
// just don't crash
}
}
This is only working correctly when I step into Task.Run but not when I step over or let it run. Perhaps there is some closure issue with the lambda being passed into the action?
You should use CancellationTokenSource
void Execute(Action action, TimeSpan timeout)
{
var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);
try
{
Task.Run(action, cts.Token).Wait();
}
catch (TaskCanceledException e)
{
//here you know the task is cancelled due to timeout
}
}

how to stop async method execution in c#?

I am using an asynchronous method. How can I stop its execution when a Timer raises a timeout event?
My code:
public async Task<object> Method()
{
cts = new CancellationTokenSource();
try
{
timer = new System.Timers.Timer(3000);
timer.Start();
timer.Elapsed += (sender, e) =>
{
try
{
timer_Elapsed(sender, e, cts.Token, thread);
}
catch (OperationCanceledException)
{
return;
}
catch (Exception ex)
{
return;
}
};
await methodAsync(cts.Token);
return "message";
}
catch (OperationCanceledException)
{
return "cancelled";
}
catch (Exception ex)
{
return ex.Message;
}
}
// Async Call
public async Task<object> methodAsync(CancellationToken ct)
{
try
{
pdfDocument = htmlConverter.Convert("path", "");
}
catch(Exception ex)
{
return x.Message;
}
}
// Timer event
void timer_Elapsed(object sender, ElapsedEventArgs e, CancellationToken ct)
{
cts.Cancel();
ct.ThrowIfCancellationRequested();
}
Here's how canceling a task works:
public async Task<object> Method()
{
cts = new CancellationTokenSource();
await methodAsync(cts.Token);
return "message";
}
public Task<object> methodAsync(CancellationToken ct)
{
for (var i = 0; i < 1000000; i++)
{
if (ct.IsCancellationRequested)
{
break;
}
//Do a small part of the overall task based on `i`
}
return result;
}
You have to respond to the change in the property of ct.IsCancellationRequested to know when to cancel the task. There is no safe way for one thread/task to cancel another thread/task.
In your case it appears that you are trying to call a single method that doesn't know about the CancellationToken so you can not cancel this task safely. You must let the thread/task continue to completion.
I think you can try mentioning when to cancel it. Something like
cts.CancelAfter(TimeSpan.FromMilliseconds(5000));
Also, you need to use the cancellation token in the called methods. That's when you will know when to cancel.

Best approach for cancel an awaitable method before navigation?

I am working in Xamarin app, but I think my question is more focused in .NET framework and C#.
For example I navigate to PageOne, and in constructor is called the asynchronous method InitializePageOneData()...
public PageOne()
{
await InitializePageOneData()
}
But just in this moment, while it is waiting for the method execution, I navigate to a second page (PageTwo), which has another asynchronous operations, but I see that the InitializePageOneData() method does not stops his execution.
My goal is to stop this asynchronous operation before doing the navigation to another page. What is your recommendation?
Note: in the asynchronous operation, I am using TaskCompletionSource:
private Task<Response> ProcessRequest(Request request)
{
tsc = new TaskCompletionSource<Response>();
eventHandler = (s, e) =>
{
try
{
_client.ProcessRequestsCompleted -= eventHandler;
tsc.TrySetResult(e.Result);
}
catch (Exception ex)
{
_client.ProcessRequestsCompleted -= eventHandler;
tsc.TrySetException(ex);
}
};
_client.ProcessRequestsCompleted += eventHandler;
_client.ProcessRequestsAsync(request);
return tsc.Task;
}
My goal is to stop this asynchronous operation before doing the
navigation to another page. What is your recommendation?
Pass down a CancellationToken to your async method, and monitor on that token. If the user wants to navigate away to page two, use the CancellationTokenSource to cancel that operation.
An example would be:
private CancellationTokenSource cts = new CancellationTokenSource();
public async Task LoadPageOneAsync()
{
try
{
await InitializePageOneDataAsync(cts.Token)
}
catch (OperationCanceledException e)
{
// Handle if needed.
}
}
public async Task InitializePageOneDataAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
foreach (var something in collection)
{
cancellationToken.ThrowIfCancellationRequested();
// Do other stuff
}
}
When you want to cancel, invoke cts.Cancel() from PageTwo:
public async Task LoadPageTwoAsync()
{
cts.Cancel();
cts = new CancellationTokenSource();
await LoadSecondPageAsync();
}

Categories

Resources