Use try/catch block on called functions or task.wait()? - c#

what's the difference between using try catch surrounding a function block that is called by some task and calling try/catch on task.wait(). If i take care of exceptions within the function, do i still need to worry about any exception that might occur from task.wait() ?
var factory = new TaskFactory();
task t1= factory.StartNew(() => funA();
t1.Wait();
void funcA()
{
try{..}
.
.
catch{..}
}
Or
var factory = new TaskFactory();
task t1= factory.StartNew(() => funA();
try
{
t1.Wait();
}
catch{....}
void funcA()
{
}

With the first block you provided you wouldn't be able to catch any of these exceptions that may occur:
ObjectDisposedException: The Task has been disposed.
ArgumentOutOfRangeException: timeout is a negative number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater than MaxValue.
AggregateException: The Task was canceled -or- an exception was thrown during the execution of the Task.
From Task.Wait() documentation on MSDN

I use to handle exceptions in tasks with continuations, easier IMO:
Task myTask= Task.Factory.StartNew( ... ).ContinueWith(myTaskFinished=>
{
if (myTaskFinished.IsCompleted)
{
// Hooray
}
if (myTaskFinished.IsFaulted)
{
foreach (Exception ex in myTaskFinished.Exception.InnerExceptions)
//Exception handle..
}
if(myTaskFinished.IsCanceled)
{
//Cancellation token?
}
});
myTask.Wait();

Related

WaitAll vs WaitAny

I am little bit confuse for WaitAll and WaitAny. I am trying to get exception but when i do WaitAll it return exception but When use WaitAny returns nothing.And necessary is that if any of task complete work done.Is their any Replacement of WaitAny(). WaitAll and WhenAll are different becuase i dont want let all task done. Like
try
{
int i = 0;
Task t1 = Task.Factory.StartNew(() =>
{
i = 2 * 4;
});
Task<int> t2 = Task.Factory.StartNew(() =>
{
int a = 0;
int b = 100 / a;
return 0;
});
Task[] tasks = new Task[] { t1, t2 };
Task.WaitAny(tasks);
//Task.WaitAll(tasks);// Working
}
catch (AggregateException ae)
{
var message = ae.InnerException.Message;
Console.WriteLine(message);
}
Console.ReadLine();
This is called Unobserved Exception, which basically means that exception in newly created threads in Task Parallel Library (TPL) ThreadPool, is not caught by the other thread or as stated in aforementioned link:
While unobserved exceptions will still cause the
UnobservedTaskException event to be raised (not doing so would be a
breaking change), the process will not crash by default. Rather, the
exception will end up getting eaten after the event is raised,
regardless of whether an event handler observes the exception.
This means that when using WaitAny(), if one of the tasks completes without any exception, exceptions in other tasks will not be caught.
Maybe you want something like this. Note, this uses the Task-based Asynchronous Pattern.
public static Task<Task[]> WhenAllOrFirstException(params Task[] tasks)
{
var countdownEvent = new CountdownEvent(tasks.Length);
var completer = new TaskCompletionSource<Task[]>();
Action<Task> onCompletion = completed =>
{
if (completed.IsFaulted && completed.Exception != null)
{
completer.TrySetException(completed.Exception.InnerExceptions);
}
if(countdownEvent.Signal() && !completer.Task.IsCompleted)
{
completer.TrySetResult(tasks);
}
};
foreach(var task in tasks)
{
task.ContinueWith(onCompletion)
}
return completer.Task;
}
Your WaitAny implementation will throw error as well it depends what task will complete first. WaitAny does not wait till looser task (in most cases it would be t2) got completed - so it won't got exception from it.
Update
Indeed WaitAny will not return any error as descriobed here Task.WhenAny and Unobserved Exceptions

How to propagate an Exception from a Task / Thread to the method that created this Task in c#?

I do not know how I should properly propagate an exception from a Task to the thread that created this task:
private void threadMT()
{
Task task;
try
{
task = new Task(() =>
{
throw new Exception("blabla");
});
task.Start();
while(!task.IsCompleted)
Thread.Sleep(500);
if (task.IsFaulted)
throw task.Exception;
}
catch (Exception ex)
{
throw ex;
}
}
When this line is reached:
throw new Exception("blabla");
the app halts saying that the exception is not handled.
Can it be propagated back to method?
Thx in advance.
The easiest way for you to propagate an exception from a Task executed on the thread-pool is to turn it to actually return a Task which you can await on:
public async Task AwaitOnTaskAsync()
{
try
{
await DoStuffWithThreadAsync();
}
catch (Exception e)
{
}
}
public Task DoStuffWithThreadAsync()
{
return Task.Run(() => { throw new Exception("blabla"); });
}
await will make sure to unwrap the exception out of the Task, allowing you to apply a try-catch on it.
Side Note - Don't use the Task constructor, instead use Task.Run to return a "hot task" (one which has already started). There's no point in creating a Task which you're actively blocking on using Thread.Sleep later on, either execute it synchronously or use async-await to asynchronously wait on the task.

Exception is not caught at Cancelation of Task.Run

I have a class Worker which is doing some work (with simulated workload):
public class Worker
{ ...
public void DoWork(CancellationToken ct)
{
for (int i = 0; i < 10; i++)
{
ct.ThrowIfCancellationRequested();
Thread.Sleep(2000);
}
}
Now I want to use this method in a Task.Run (from my Windows Forms App,at button-click) which can be cancelled:
private CancellationTokenSource _ctSource;
try
{
Task.Run(() =>
{
_worker.DoWork(_ctSource.Token);
},_ctSource.Token);
}
catch (AggregateException aex)
{
String g = aex.Message;
}
catch (OperationCanceledException ex)
{
String g = ex.Message;
}
catch (Exception ex)
{
String g = ex.Message;
}
But when the task is started, I can't cancel it with _ctSource.Cancel();
I get an error in visual studio that the OperationCanceledException is not handled!
But I surrounded the Task.Run Call in a try-catch-clause! The Exception which ocurrs in the Worker object should thrown up or not?
What is the problem?
Your Task.Run call creates the task and then returns immediately. It doesn't ever throw. But the task it creates may fail or be canceled later on.
You have several solutions here:
Use await:
await Task.Run(...)
Attach a continuation depending on the failure/cancellation case:
var task = Task.Run(...);
task.ContinueWith(t => ..., TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(t => ..., TaskContinuationOptions.OnlyOnFaulted);
Attach a single continuation on failure:
Task.Run(...).ContinueWith(t => ..., TaskContinuationOptions.NotOnRanToCompletion);
The solution you can/should use depends on the surrounding code.
You need to new the token
private CancellationTokenSource _ctSource = new CancellationTokenSource();
Why are throwing an expectation in DoWork?
Exception from one thread don't bubble up another thread that started the thread.
Cancellation in Managed Threads
If a parallel Task throws an exception it'll return execution and will have it's Exception property (as an AggregateException, you should check for its InnerException) set (and either its IsCanceled or IsFaulted property set to true). Some minimal sample code from a project of mine which escalates the exception to the main thread:
var t = new Task(Initialize);
t.Start();
while (!t.IsCompleted && !t.IsFaulted)
{
// Do other work in the main thread
}
if (t.IsFaulted)
{
if (t.Exception != null)
{
if(t.Exception.InnerException != null)
throw t.Exception.InnerException;
}
throw new InvalidAsynchronousStateException("Initialization failed for an unknown reason");
}
If you use a CancellationTokenSource it should be easy to enhance this to check for IsCanceled (instead of IsFaulted)
You can also use Task.Wait() instead of the while loop... in my project and in that precise case it seemed more appropiate to use the while loop, but you need to wait for the Task to end in one way or another.
If you use Task.Run() you can use a .ContinueWith(Task) which will have the original task passed in (where you can check for IsFaulted or IsCanceled), or have it run only on faulted execution, at your will.

is it possible to catch when any Task terminates due exception and log?

Is it possible to catch when any Task terminates due exception and log? I've added CurrentDomain_UnhandledException handling but this doesn't help.
I create tasks using Task.Factory.StartNew() as usual. When somewhere inside such task exception occurs it crashes silently (but it supposed to work forever, i'm also using LongRunning option). So I want to be notified about such behavior.
Ideallly I want to set some option somewhere to be notified when any Task crashes due exception.
If it is not possible then likely I should add something to each Task I create? Of course I can just add big try{} finally{} block inside each Task, but probably there are better solutions?
Assuming you have a Test as Task to run:
static int Test()
{
throw new Exception();
}
First Approach - Process exception in the caller's thread:
Task<int> task = new Task<int>(Test);
task.Start();
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex);
}
Note: The exception will be of type AggregateException. All actual exceptions are available through ex.InnerExceptions property.
Second Approach - Process exception in some task's thread:
Define the ExceptionHandler this way:
static void ExceptionHandler(Task<int> task)
{
var ex = task.Exception;
Console.WriteLine(ex);
}
Usage:
Task<int> task = new Task<int>(Test);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Reference: How to: Handle Exceptions Thrown by Tasks
For tasks that you create yourself, it's reasonably simple: create your own methods which call Task.Factory.StartNew(), but then also call Task.ContinueWith(loggingDelegate, TaskContinuationOptions.OnlyOnFaulted before returning the task.
The problem is that that won't add a fault handler for tasks created by other bits of infrastructure - including by async methods in C# 5. It still might be useful to you though.
You can also use TaskScheduler.UnobservedTaskException, but as per the name that will only be called for exceptions which aren't already observed by something else. (Again, that may be fine for you...)
You can use an extension method that performs an operation when an exception has ocurred.
This happens when the Task gets Faulted. So if it has another tasks to continue with, the next one can check if the previous task was faulted and Log the exception.
I usually use this methods:
//If you want to chain more tasks..
public static Task<T> Continue<T>(this Task<T> task, Action<T> action)
{
if (!task.IsFaulted)
{
task.ContinueWith((t) => action(t.Result), TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion);
}
return task;
}
public static Task OnException(this Task task, Action<Exception> onFaulted)
{
task.ContinueWith(c =>
{
var excetion = c.Exception;
onFaulted(excetion);
},
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
return task;
}
So you can use:
Task.Factory.StartNew(...).OnException(ex => Log(ex));
Hope it helps.
Wrap your task.Wait() in a try/catch block and catch AggregateException. Something like this -
Task<string[]> task1 = Task<string[]>.Factory.StartNew(() => GetAllFiles(path));
// Use this line to throw an exception that is not handled.
try
{
task1.Wait();
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is UnauthorizedAccessException) // This we know how to handle.
{
Console.WriteLine("You do not have permission to access all folders
in this path.");
Console.WriteLine("See your network administrator or try
another path.");
return true;
}
return false; // Let anything else stop the application.
});
}
Details can be found here - Handle exceptions thrown by Task.
You can create a OnlyOnFaulted continuation on your Task which observes the exception and logs/reports the problem.
t.ContinueWith(task =>
{
// Report and log error
}, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
The above code will run the task on the UI thread because of TaskScheduler.FromCurrentSynchronizationContext(). This may be necessary if you are using winforms and need to notify the user.

Using Tasks with conditional continuations

I'm a little confused about how to use Tasks with conditional Continuations.
If I have a task, and then I want to continue with a tasks that handle success and error, and then wait on those to complete.
void FunctionThrows() {throw new Exception("faulted");}
static void MyTest()
{
var taskThrows = Task.Factory.StartNew(() => FunctionThrows());
var onSuccess = taskThrows.ContinueWith(
prev => Console.WriteLine("success"),
TaskContinuationOptions.OnlyOnRanToCompleted);
var onError = taskThrows.ContinueWith(
prev => Console.WriteLine(prev.Exception),
TaskContinuationOptions.OnlyOnFaulted);
//so far, so good
//this throws because onSuccess was cancelled before it was started
Task.WaitAll(onSuccess, onError);
}
Is this the preferred way of doing task success/failure branching? Also, how am I supposed to join all these tasks, suppose I've created a long line of continuations, each having their own error handling.
//for example
var task1 = Task.Factory.StartNew(() => ...)
var task1Error = task1.ContinueWith( //on faulted
var task2 = task1.ContinueWith( //on success
var task2Error = task2.ContinueWith( //on faulted
var task3 = task2.ContinueWith( //on success
//etc
Calling WaitAll on these invariably throws, because some of the continuations will be cancelled due to the TaskContinuationOptions, and calling Wait on a cancelled task throws.
How do I join these without getting the "A task was cancelled" exception"?
I think your main problem is that you're telling those two tasks to "Wait" with your call to
Task.WaitAll(onSuccess, onError);
The onSuccess and onError continuations are automatically setup for you and will be executed after their antecedent task completes.
If you simply replace your Task.WaitAll(...) with taskThrows.Start(); I believe you will get the desired output.
Here is a bit of an example I put together:
class Program
{
static int DivideBy(int divisor)
{
Thread.Sleep(2000);
return 10 / divisor;
}
static void Main(string[] args)
{
const int value = 0;
var exceptionTask = new Task<int>(() => DivideBy(value));
exceptionTask.ContinueWith(result => Console.WriteLine("Faulted ..."), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
exceptionTask.ContinueWith(result => Console.WriteLine("Success ..."), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);
exceptionTask.Start();
try
{
exceptionTask.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine("Exception: {0}", ex.InnerException.Message);
}
Console.WriteLine("Press <Enter> to continue ...");
Console.ReadLine();
}
}
Use Task.WaitAny(onSuccess, onError);
Isn't that normal?
Looking at the MSDN documentation you're doing it fine and the logic you're implementing is sound. The only thing you're missing is wrapping the WaitAll call in an AggregateException wrapper like so:
// Exceptions thrown by tasks will be propagated to the main thread
// while it waits for the tasks. The actual exceptions will be wrapped in AggregateException.
try
{
// Wait for all the tasks to finish.
Task.WaitAll(tasks);
// We should never get to this point
Console.WriteLine("WaitAll() has not thrown exceptions. THIS WAS NOT EXPECTED.");
}
catch (AggregateException e)
{
Console.WriteLine("\nThe following exceptions have been thrown by WaitAll(): (THIS WAS EXPECTED)");
for (int j = 0; j < e.InnerExceptions.Count; j++)
{
Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());
}
}
You can read more here:
http://msdn.microsoft.com/en-us/library/dd270695.aspx
In essence catching an AggregatedException gets you the same thing as completing WaitAll. It's a collection of all the exceptions returned from your tasks.

Categories

Resources