Using Tasks with conditional continuations - c#

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.

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 break the chain of Task when an exception occurs?

I create the chain of the works. They are to work inside of my additional thread. I use the Task for this purpose. Also, I want to break the chain's work if any exception occurred and throw it in the calling thread. But I see my chain wasn't broken and the act2 with act3 was completed too.
How can I fix it?
using System;
using System.Threading.Tasks;
namespace Bushman.Sandbox.Threads {
class Program {
static void Main(string[] args) {
Console.Title = "Custom thread";
try {
// First work
Action act1 = () => {
for (int i = 0; i < 5; i++) {
// I throw the exeption here
if (i == 3) throw new Exception("Oops!!!");
Console.WriteLine("Do first work");
}
};
// Second work
Action act2 = () => {
for (int i = 0; i < 5; i++)
Console.WriteLine(" Do second work");
};
// Third work
Func<int> act3 = () => {
for (int i = 0; i < 5; i++)
Console.WriteLine(" Do third work");
return 12345;
};
Task task = new Task(act1);
// Build the chain of the works
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously)
.GetAwaiter();
Console.WriteLine("Work started...");
// launch the chain
task.Start();
// Here I get some result
int result = awaiter.GetResult(); // 12345
if (task.IsCanceled || task.IsFaulted) {
throw task.Exception.InnerException;
}
Console.WriteLine("The result: {0}",
result.ToString());
}
catch (Exception ex) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
}
Console.WriteLine("Press any key for exit...");
Console.ReadKey();
}
}
}
You have to use the NotOnFaulted Task Continuation Option.
Since TaskContinuationOptions is decorated with the Flags attribute, you can combine NotFaulted with other options.
var awaiter = task.ContinueWith(_ => act2(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.ContinueWith(_ => act3(),
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted)
.GetAwaiter();
Even if you are using the async/await keywords, this approach is still valid (but you get rid of GetAwaiter call)
The code is trying to use tasks in an unconventional way, almost as if they were threads. They aren't - tasks are a job that will get scheduled to run on a threadpool thread, not the thread itself. Calling Task.Start won't execute anything, it will schedule its delegate to run on a thread. That's why tasks are never created using the constructor.
The easiest way to start and coordinate tasks is to use Task.Run and async/await, eg:
public static async Task<int> MyMethodAsync()
{
try
{
await Task.Run(()=>act1());
await Task.Run(()=>act2());
var result=await Task.Run(()=>act3());
return result;
}
catch (Exception exc)
{
//Do something
}
}
You can't use async/await on a console application's Main function, so you'll have to call the method in the following way:
var result=MyMethodAsync().Result;
Calling .Wait() or .Result on a task rethrows any exceptions raised inside it.
Without async/await, you'd need to use ContinueWith and actually check the result of the previous task. If you simply want to stop processing, you can pass TaskContinuationOptions.NotOnFaulted :
var result = Task.Run(()=>act1())
.ContinueWith( t1=>act2(),TaskContinuationOptions.NotOnFaulted)
.ContinueWith( t2=>act3(),TaskContinuationOptions.NotOnFaulted)
.Result;
You don't need to get explicit access to the awaiter. The final call to .Result will either return the integer result or throw an AggregateException if one of the previous tasks faulted

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.

How to make Task.WaitAll() to break if any exception happened?

I want to make Task.WaitAll() to break out if any of the running tasks throws an exception, so that I don't have to wait for 60 seconds to finish. How do I achieve such behavior? If WaitAll() cannot achieve that, is there any other c# feature or workaround?
Task task1 = Task.Run(() => throw new InvalidOperationException());
Task task2 = ...
...
try
{
Task.WaitAll(new Task[]{task1, task2, ...}, TimeSpan.FromSeconds(60));
}
catch (AggregateException)
{
// If any exception thrown on any of the tasks, break out immediately instead of wait all the way to 60 seconds.
}
The following should do it without altering the code of the original tasks (untested):
static bool WaitAll(Task[] tasks, int timeout, CancellationToken token)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
var proxyTasks = tasks.Select(task =>
task.ContinueWith(t => {
if (t.IsFaulted) cts.Cancel();
return t;
},
cts.Token,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Current).Unwrap());
return Task.WaitAll(proxyTasks.ToArray(), timeout, cts.Token);
}
Note it only tracks faulted tasks (those which threw). If you need to track cancelled tasks as well, make this change:
if (t.IsFaulted || t.IsCancelled) cts.Cancel();
Updated, waiting on the task proxies is redundant here, as pointed out by #svick in the comments. He proposes an improved version: https://gist.github.com/svick/9992598.
One way of doing that is to use CancellationTokenSource. You create cancellationtokensource, and pass it as an argument to Task.WaitAll. The idea is to wrap your task in try/catch block, and in case of exception, call cancel on cancellationtokensource.
Here's sample code
CancellationTokenSource mainCancellationTokenSource = new CancellationTokenSource();
Task task1 = new Task(() =>
{
try
{
throw new Exception("Exception message");
}
catch (Exception ex)
{
mainCancellationTokenSource.Cancel();
}
}, mainCancellationTokenSource.Token);
Task task2 = new Task(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(3));
Console.WriteLine("Task is running");
}, mainCancellationTokenSource.Token);
task1.Start();
task2.Start();
Task.WaitAll(new[] { task1, task2},
6000, // 6 seconds
mainCancellationTokenSource.Token
);
}
catch (Exception ex)
{
// If any exception thrown on any of the tasks, break out immediately instead of wait all the way to 60 seconds.
}
Parallel class can do the job for you. You can use Parallel.For, ForEach or Invoke.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Sample_04_04_2014_01
{
class Program
{
public static void Main(string[] args)
{
try
{
Parallel.For(0,20, i => {
Console.WriteLine(i);
if(i == 5)
throw new InvalidOperationException();
Thread.Sleep(100);
});
}
catch(AggregateException){}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
If one of these tasks throws an exception then no other task will be executed excepting those whose execution was already started. For, ForEach and Invoke are waiting for all tasks to complete before to resume control to the calling code. You can have even a finer grain control if you use ParallelLoopState.IsExceptional. Parallel.Invoke is more suited for your case.
I wanted to suggest a slight modification to Noseratio's excellent answer above. In my case I needed to preserve the original exception thrown, and in a surrounding try/catch distinguish between cancelled and exception states.
public static void WaitUnlessFault( Task[] tasks, CancellationToken token )
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
foreach ( var task in tasks ) {
task.ContinueWith(t =>
{
if ( t.IsFaulted ) cts.Cancel();
},
cts.Token,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Current);
}
try {
Task.WaitAll(tasks, cts.Token);
}
catch ( OperationCanceledException ex ) {
var faultedTaskEx = tasks.Where(t => t.IsFaulted)
.Select(t => t.Exception)
.FirstOrDefault();
if ( faultedTaskEx != null )
throw faultedTaskEx;
else
throw;
}
}

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

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();

Categories

Resources