I have a Task by heavy process runs in that's body. In addition, we have no access to the body of this method (heavy process) and we must wait until to completion the process.
Now my question is, how do I cancel without interrupting the task so that I do not check any value in it?
My codes like this:
private CancellationTokenSource CTS = new CancellationTokenSource();
public void CallMyMethod(CancellationTokenSource cts)
{
//
// Several methods they call each other. And pass tokens to each other.
MyProcess(cts);
}
private void MyProcess(CancellationTokenSource cts)
{
CancellationToken token = cts.Token;
Task.Run(() =>
{
token.ThrowIfCancellationRequested(); // Work just when ThrowIfCancellationRequested called. and check that again
if (token.IsCancellationRequested) // Must be checked every time, and after the investigation not work.
return;
// My long time process
HeavyProcess(); // We have no access to the body of this method
}, token);
}
private void CancelProcess()
{
try
{
//
// I want to cancel Now, Just Now not after HeavyProcess completion or checking token again!
//
CTS.Cancel();
CTS.Token.ThrowIfCancellationRequested();
}
catch
{ }
}
Can I cancel the heavy process after that running ?
If you can't control the long running method, then cooperative cancellation isn't going to work. What you can do is offload the heavy job to a different process, and monitor on the process in a background thread:
private void MyProcess(CancellationTokenSource cts)
{
cts.Token.ThrowIfCancellationRequested();
// Move the heavy work to a different process
var process = Process.Start(new ProcessStartInfo { /* */ });
// Register to the cancellation, where if the process is still
// running, kill it.
cts.Token.Register(() =>
{
if (!process.HasExited)
{
process.Kill();
}
});
}
And now, when you cancel, you invoke the callback where we terminate the process:
private void CancelProcess()
{
CTS.Cancel();
}
Related
How do I allow the current thread to safely exit and perform a delete action to some resources of the thread?
I used Thread.Abort() but using that it seems that it does not release the resources. I am finding a way to allow the thread to safely exit and as soon as it exits, I want to perform the delete action.
I am writing it using C#, if any one has any examples or suggestions please contribute.
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
var task = Task.Run(() => dssPut_Command("Compile " + SystemID + "abc.dss"), tokenSource2.Token);
if (!task.Wait(TimeSpan.FromSeconds(2)))
{
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
while (moreToDo)
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
tokenSource2.Cancel();
}
}
The best way to go about this depends on your scenario, but one of my preferred ways is usually to use a CancellationToken to signal that the thread should exit gracefully.
This avoids using Thread.Abort() (which is generally not a good idea), and it allows your worker to decide when it is appropriate to cancel and it can perform any necessary clean-up.
In the code you've posted, the method that calls Task.Run() should only create the CancellationTokenSource, pass the CancellationToken into the dssPut_Command method, and set cts.CancelAfter() to set the timeout. Then, only the code inside the method dssPut_Command should be checking if cancellation is requested.
static void Main()
{
using (var cts = new CancellationTokenSource())
{
// Start the worker thread and pass the
// CancellationToken to it
Console.WriteLine("MAIN: Starting worker thread");
var worker = Task.Run(() => dssPut_Command(cts.Token));
// Make the token cancel automatically after 3 seconds
cts.CancelAfter(3000);
// Wait for worker thread to exit
Console.WriteLine("MAIN: Waiting for the worker to exit");
worker.Wait();
Console.WriteLine("MAIN: Main thread exiting after worker exited");
}
}
static void dssPut_Command(object tokenObj)
{
Console.WriteLine("WORKER: Worker thread started");
var cancellationToken = (CancellationToken)tokenObj;
// You can check if cancellation has been requested
if (cancellationToken.IsCancellationRequested)
{
// If there's no need to clean up, you can just return
return;
}
try
{
// Or you can throw an OperationCanceledException automatically
cancellationToken.ThrowIfCancellationRequested();
// Pass the CancellationToken to any methods you call
// so they can throw OperationCanceledException when
// the token is canceled.
DoWork(cancellationToken);
}
catch (OperationCanceledException)
{
// Do any clean-up work, if necessary
Console.WriteLine("WORKER: Worker exiting gracefully");
}
}
static void DoWork(CancellationToken cancellationToken)
{
// Simulating a long running operation
Task.Delay(TimeSpan.FromMinutes(1), cancellationToken).GetAwaiter().GetResult();
}
How can I ensure a single active Task is always killed and replaced on each call to the method that starts the Task.Run?
The idea is to only ever have 1 future notification waiting to be shown (last caller's), no matter how many times the method (SetFutureNotification) is called (or how rapidly).
When debugging and calling the method (rapidly), let's say, 5 times, I am seeing very odd results.
For example: The 2nd callers Task is running and the subsequent callers tasks are cancelled (exited).
The expected behavior is for the last caller's Task to be running (5th caller) and all previous callers Task's cancelled (exited).
By placing a small delay between each of the 5 test calls (500ms), I get the desired result, however I am wanting to learn the correct approach.
public static class NotificationsHelper
{
private static CancellationTokenSource _cts = new CancellationTokenSource();
// Set Future Notification (From outside this class).
// If called multiple times, the existing task should be killed and a new task replaces it.
public static void SetFutureNotification(string notificationText, DateTime notificationDateTime, Action<string> notificationAction)
{
CancelNotification();
_cts = new CancellationTokenSource();
Task.Run(async () =>
{
while (!_cts.Token.IsCancellationRequested)
{
await Task.Delay(1000, _cts.Token);
if (DateTime.Now > notificationDateTime)
{
notificationAction?.Invoke(notificationText);
_cts.Cancel();
}
}
}, _cts.Token);
}
// Cancel Active Future Notification (From outside this class).
public static void CancelNotification()
{
if (_cts != null && _cts.Token != null && _cts.Token.CanBeCanceled == true)
{
_cts.Cancel();
}
}
}
Edit:
I reformatted my code to test the proposed answer by Oleg (below) by adding an Id to keep track of the tasks. This confirmed the desired result:
public static class NotificationsHelper
{
private static int _counter = 0;
private static CancellationTokenSource _cts;
// Set Future Notification (From Anywhere).
// If called multiple times, the existing task should be killed and a new task replaces it.
public static void SetFutureNotification(string notificationText, DateTime notificationDateTime, Action<string> notificationAction)
{
_counter += 1;
var id = _counter.ToString();
Console.WriteLine("Method Called: " + id);
CancelNotification();
_cts = new CancellationTokenSource();
var cts = _cts; // I'm local cts and will be captured by one task only
Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
await Task.Delay(1000, cts.Token);
if (DateTime.Now > notificationDateTime)
{
notificationAction?.Invoke(notificationText);
cts.Cancel();
}
Console.WriteLine("Task active: " + id);
}
}, cts.Token).ContinueWith(t => { Console.WriteLine("Task exited: " + id); });
}
// Cancel Notification (From Anywhere).
public static void CancelNotification()
{
if (_cts != null && _cts.Token != null && _cts.Token.CanBeCanceled == true)
{
_cts.Cancel();
}
}
}
It looks your intention was to cancel every task before starting new one, and its done almost right - the problem is that every task captures and checks same member variable _cts that all tasks share. Even though you new it for every notification, after your delay (1000) all of them are aware of only last one you've created. What you need is to have every task to have own copy of cancellation token, the one you would be cancelling on every subsequent task:
public static void SetFutureNotification(string notificationText, DateTime notificationDateTime, Action<string> notificationAction)
{
CancelNotification();
_cts = new CancellationTokenSource();
var cts = _cts; // I'm local cts and will be captured by one task only
Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
await Task.Delay(1000, cts.Token);
if (DateTime.Now > notificationDateTime)
{
notificationAction?.Invoke(notificationText);
cts.Cancel();
}
}
}, cts.Token);
}
Now, your cancellation routine (that does not need a change) will be canceling the last task created, and only last task would know about it
Your problem is that the cancelling the CancellationToken will signal only that a cancellation is required to the background task. However that task will continue to run for a certain amount of time, up to a point where the CancellationToken is checked and the cancellation is processed.
If you want to make sure the task is fully cancelled, you need to wait for it to finish after you cancel the token:
// When starting the task:
_currentTask = Task.Run(async () => ...);
// in Cancel method:
if (_cts != null && _cts.Token != null && _cts.Token.CanBeCanceled == true)
{
_cts.Cancel();
// Wait for the background task to finish.
// Maybe with a try/catch block around it, because it might throw a
// Cancellation exception
await _currentTask;
_cts = null;
_currentTask = null;
}
This should work if you always start and try to cancel background tasks from the same thread (e.g. UI thread). If these operations happen from different threads, you might also need to protect _cts and _currentTask, e.g. with an awaitable Mutex.
If you don't care about whether the background task is still running, and just want to let it finish at some point of time, then the approach outlined by Oleg Bogdanov with capturing the current CancellationToken in the background task will also work.
I have a C# windows form application. I want to update some labels by fetching information from the web. I want to call a function periodically using BackgroundWorker.
public partial class OptionDetails : Form
{
static System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
static void fun()
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{ // some work }
static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{ // on completion }
}
If I use Timer, the UI hangs. How do I use BackgroundWorker to call worker_DoWork periodically?
My actual code:
public partial class myform: Form
{
public myform()
{
InitializeComponent();
}
public async Task Periodic(Action func, TimeSpan period, CancellationToken token)
{
while (true)
{
// throws an exception if someone has requested cancellation via the token.
token.ThrowIfCancellationRequested();
func();
// asynchronously wait
await Task.Delay(period);
}
}
public async void hello()
{
await Periodic(getCurrentInfo, TimeSpan.FromSeconds(2), CancellationToken.None);
}
private void myform_Load(object sender, EventArgs e)
{
hello();
}
private void getCurrentInfo()
{
WebDataRetriever wdr = new WebDataRetriever();
string name = "name";
string url = String.Empty;
string[] prices = new string[2];
bool urlExists = url.TryGetValue(name, out url);
if (urlExists)
{
wdr.processurl(); // time consuming function
prices[0] = wdr.price1;
prices[1] = wdr.price2;
System.Globalization.NumberFormatInfo nfo = new System.Globalization.CultureInfo("en-US", false).NumberFormat;
if (prices != null)
{
// change labels
}
}
}
}
The simplest solution for what you need is probably to use a Timer to kick off BackgroundWorker, but using async/await I believe results in a more compact and elegant solution.
The solution below is an asynchronous method, for which the compiler generates a state machine. When the asynchronous method Periodic is invoked it starts executing up until the first await statement. In this case this is:
await Task.Delay(period);
The expression awaited returns an awaitable, which is in this case a Task, but it can be anything that has a method GetAwaiter which returns a type implementing the INotifyCompletion interface or the ICriticalNotifyCompletion interface.
If this task is complete the method continues executing synchronously, if the task is not complete the method returns. Once the task is complete, execution of the method resumes after that await statement in the same SynchronizationContext. If you called this from a GUI thread, execution will resume in the GUI thread, but for your case it will resume on a ThreadPool thread because console apps do not have a SynchronizationContext.
Task.Delay(period) returns a Task that becomes complete when the period elapses. I.e. it is like an asynchronous version of Thread.Sleep so execution of the while loop resumes after period expires.
The end result is that the loop runs forever periodically checking for cancellation (in which case an OperationCancelledException is thrown) and executing func.
public static async Task Periodic(Action func, TimeSpan period, CancellationToken token)
{
while(true)
{
// throws an exception if someone has requested cancellation via the token.
token.ThrowIfCancellationRequested();
func();
// asynchronously wait
await Task.Delay(period);
}
}
In a GUI app you can use it like this:
await Periodic(() => /* do something clever here*/, TimeSpan.FromSeconds(1), CancellationToken.None);
The main method of a console app cannot be asynchronous so you cannot use await but you can call Wait() on the result instead to run it indefinitely and prevent the application from exiting.
void Main()
{
Periodic(() => Console.WriteLine("Hello World!"), TimeSpan.FromSeconds(1), CancellationToken.None).Wait();
}
Care must be taken when calling Wait() in a GUI app as it can result in a deadlock.
Update
You may also benefit from having an overload of Periodic that takes an async func, in case you have an expensive time consuming function you want to run in the background.
public async Task Periodic(Func<Task> func, TimeSpan period, CancellationToken token)
{
while (true)
{
// throws an exception if someone has requested cancellation via the token.
token.ThrowIfCancellationRequested();
await func();
// asynchronously wait
await Task.Delay(period);
}
}
In a thread, I create some System.Threading.Task and start each task.
When I do a .Abort() to kill the thread, the tasks are not aborted.
How can I transmit the .Abort() to my tasks ?
You can't. Tasks use background threads from the thread pool. Also canceling threads using the Abort method is not recommended. You may take a look at the following blog post which explains a proper way of canceling tasks using cancellation tokens. Here's an example:
class Program
{
static void Main()
{
var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;
Task.Factory.StartNew(() =>
{
while (true)
{
// do some heavy work here
Thread.Sleep(100);
if (ct.IsCancellationRequested)
{
// another thread decided to cancel
Console.WriteLine("task canceled");
break;
}
}
}, ct);
// Simulate waiting 3s for the task to complete
Thread.Sleep(3000);
// Can't wait anymore => cancel this task
ts.Cancel();
Console.ReadLine();
}
}
Like this post suggests, this can be done in the following way:
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
Although it works, it's not recommended to use such approach. If you can control the code that executes in task, you'd better go with proper handling of cancellation.
Aborting a Task is easily possible if you capture the thread in which the task is running in. Here is an example code to demonstrate this:
void Main()
{
Thread thread = null;
Task t = Task.Run(() =>
{
//Capture the thread
thread = Thread.CurrentThread;
//Simulate work (usually from 3rd party code)
Thread.Sleep(1000);
//If you comment out thread.Abort(), then this will be displayed
Console.WriteLine("Task finished!");
});
//This is needed in the example to avoid thread being still NULL
Thread.Sleep(10);
//Cancel the task by aborting the thread
thread.Abort();
}
I used Task.Run() to show the most common use-case for this - using the comfort of Tasks with old single-threaded code, which does not use the CancellationTokenSource class to determine if it should be canceled or not.
This sort of thing is one of the logistical reasons why Abort is deprecated. First and foremost, do not use Thread.Abort() to cancel or stop a thread if at all possible. Abort() should only be used to forcefully kill a thread that is not responding to more peaceful requests to stop in a timely fashion.
That being said, you need to provide a shared cancellation indicator that one thread sets and waits while the other thread periodically checks and gracefully exits. .NET 4 includes a structure designed specifically for this purpose, the CancellationToken.
I use a mixed approach to cancel a task.
Firstly, I'm trying to Cancel it politely with using the Cancellation.
If it's still running (e.g. due to a developer's mistake), then misbehave and kill it using an old-school Abort method.
Checkout an example below:
private CancellationTokenSource taskToken;
private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false);
void Main()
{
// Start a task which is doing nothing but sleeps 1s
LaunchTaskAsync();
Thread.Sleep(100);
// Stop the task
StopTask();
}
/// <summary>
/// Launch task in a new thread
/// </summary>
void LaunchTaskAsync()
{
taskToken = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
try
{ //Capture the thread
runningTaskThread = Thread.CurrentThread;
// Run the task
if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000))
return;
Console.WriteLine("Task finished!");
}
catch (Exception exc)
{
// Handle exception
}
}, taskToken.Token);
}
/// <summary>
/// Stop running task
/// </summary>
void StopTask()
{
// Attempt to cancel the task politely
if (taskToken != null)
{
if (taskToken.IsCancellationRequested)
return;
else
taskToken.Cancel();
}
// Notify a waiting thread that an event has occurred
if (awaitReplyOnRequestEvent != null)
awaitReplyOnRequestEvent.Set();
// If 1 sec later the task is still running, kill it cruelly
if (runningTaskThread != null)
{
try
{
runningTaskThread.Join(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
runningTaskThread.Abort();
}
}
}
To answer Prerak K's question about how to use CancellationTokens when not using an anonymous method in Task.Factory.StartNew(), you pass the CancellationToken as a parameter into the method you're starting with StartNew(), as shown in the MSDN example here.
e.g.
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task.Factory.StartNew( () => DoSomeWork(1, token), token);
static void DoSomeWork(int taskNum, CancellationToken ct)
{
// Do work here, checking and acting on ct.IsCancellationRequested where applicable,
}
You should not try to do this directly. Design your tasks to work with a CancellationToken, and cancel them this way.
In addition, I would recommend changing your main thread to function via a CancellationToken as well. Calling Thread.Abort() is a bad idea - it can lead to various problems that are very difficult to diagnose. Instead, that thread can use the same Cancellation that your tasks use - and the same CancellationTokenSource can be used to trigger the cancellation of all of your tasks and your main thread.
This will lead to a far simpler, and safer, design.
Tasks have first class support for cancellation via cancellation tokens. Create your tasks with cancellation tokens, and cancel the tasks via these explicitly.
You can use a CancellationToken to control whether the task gets cancelled. Are you talking about aborting it before it's started ("nevermind, I already did this"), or actually interrupting it in middle? If the former, the CancellationToken can be helpful; if the latter, you will probably need to implement your own "bail out" mechanism and check at appropriate points in the task execution whether you should fail fast (you can still use the CancellationToken to help you, but it's a little more manual).
MSDN has an article about cancelling Tasks:
http://msdn.microsoft.com/en-us/library/dd997396.aspx
Task are being executed on the ThreadPool (at least, if you are using the default factory), so aborting the thread cannot affect the tasks. For aborting tasks, see Task Cancellation on msdn.
I tried CancellationTokenSource but i can't do this. And i did do this with my own way. And it works.
namespace Blokick.Provider
{
public class SignalRConnectProvider
{
public SignalRConnectProvider()
{
}
public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`.
public async Task<string> ConnectTab()
{
string messageText = "";
for (int count = 1; count < 20; count++)
{
if (count == 1)
{
//Do stuff.
}
try
{
//Do stuff.
}
catch (Exception ex)
{
//Do stuff.
}
if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside.
{
return messageText = "Task stopped."; //4-) And so return and exit the code and task.
}
if (Connected)
{
//Do stuff.
}
if (count == 19)
{
//Do stuff.
}
}
return messageText;
}
}
}
And another class of the calling the method:
namespace Blokick.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MessagePerson : ContentPage
{
SignalRConnectProvider signalR = new SignalRConnectProvider();
public MessagePerson()
{
InitializeComponent();
signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property.
if (signalR.ChatHubProxy != null)
{
signalR.Disconnect();
}
LoadSignalRMessage();
}
}
}
You can abort a task like a thread if you can cause the task to be created on its own thread and call Abort on its Thread object. By default, a task runs on a thread pool thread or the calling thread - neither of which you typically want to abort.
To ensure the task gets its own thread, create a custom scheduler derived from TaskScheduler. In your implementation of QueueTask, create a new thread and use it to execute the task. Later, you can abort the thread, which will cause the task to complete in a faulted state with a ThreadAbortException.
Use this task scheduler:
class SingleThreadTaskScheduler : TaskScheduler
{
public Thread TaskThread { get; private set; }
protected override void QueueTask(Task task)
{
TaskThread = new Thread(() => TryExecuteTask(task));
TaskThread.Start();
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException(); // Unused
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException(); // Unused
}
Start your task like this:
var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);
Later, you can abort with:
scheduler.TaskThread.Abort();
Note that the caveat about aborting a thread still applies:
The Thread.Abort method should be used with caution. Particularly when you call it to abort a thread other than the current thread, you do not know what code has executed or failed to execute when the ThreadAbortException is thrown, nor can you be certain of the state of your application or any application and user state that it is responsible for preserving. For example, calling Thread.Abort may prevent static constructors from executing or prevent the release of unmanaged resources.
You can use this class..:
It works for all typs of returned Values..
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace CarNUChargeTester
{
public class TimeOutTaskRunner<T>
{
private Func<T> func;
private int sec;
private T result;
public TimeOutTaskRunner(Func<T> func, int sec)
{
this.func = func;
this.sec = sec;
}
public bool run()
{
var scheduler = new SingleThreadTaskScheduler();
Task<T> task = Task<T>.Factory.StartNew(func, (new CancellationTokenSource()).Token, TaskCreationOptions.LongRunning, scheduler);
if (!task.Wait(TimeSpan.FromSeconds(sec)))
{
scheduler.TaskThread.Abort();
return false;
}
result = task.Result;
return true;
}
public T getResult() { return result; }
}
class SingleThreadTaskScheduler : TaskScheduler
{
public Thread TaskThread { get; private set; }
protected override void QueueTask(Task task)
{
TaskThread = new Thread(() => TryExecuteTask(task));
TaskThread.Start();
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException();
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException();
}
}
To use it you can write:
TimeOutTaskRunner<string> tr = new TimeOutTaskRunner<string>(f, 10); // 10 sec to run f
if (!tr.run())
errorMsg("TimeOut"); !! My func
tr.getResult() // get the results if it done without timeout..
i have an application who take all the added files from my Listbox and play this files:
IEnumerable<string> source
public void play()
{
Task.Factory.StartNew(() =>
{
Parallel.ForEach(source,
new ParallelOptions
{
MaxDegreeOfParallelism = 1 //limit number of parallel threads
},
file =>
{
//each file process via another class
});
}).ContinueWith(
t =>
{
OnFinishPlayEvent();
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
my processing file can be stop via my class property but if i want to stop all the files
that waiting how can i do it ?
You need to design your routines to accept a CancellationToken, and then trigger a CancellationTokenSource.Cancel().
This will allow you to provide a mechanism to cooperatively cancel your work.
For details, see Cancellation in Managed Threads and Task Cancellation on MSDN.
If you want to stop a parallel loop, use an instance of the ParallelLoopState class. To cancel a task, you want to use a CancellationToken. Since you are embedding your parallel loop inside a task, you can simply pass a cancellation token into the task. Bear in mind, this will throw an OperationCanceledException you will have to catch, if you choose to wait on your task(s).
For example, and for the sake of argument, we'll assume that something else will call a delegate inside your class that will set the cancellation token.
CancellationTokenSource _tokenSource = new CancellationTokenSource();
//Let's assume this is set as the delegate to some other event
//that requests cancellation of your task
void Cancel(object sender, EventArgs e)
{
_tokenSource.Cancel();
}
void DoSomething()
{
var task = Task.Factory.StartNew(() => {
// Your code here...
}, _tokenSource.Token);
try {
task.Wait();
}
catch (OperationCanceledException) {
//Carry on, logging that the task was canceled, if you like
}
catch (AggregateException ax) {
//Your task will throw an AggregateException if an unhandled exception is thrown
//from the worker. You will want to use this block to do whatever exception handling
//you do.
}
}
Bear in mind, there are better ways to do this (and I'm typing from memory here, so there could be some syntax errors and the like), but this should get you started.