Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.ContinueWith and TaskContinuationOptions.AttachedToParent

I'm trying to use Task.ContinueWith with TaskContinuationOptions.AttachedToParent to execute a continuation task, e.g.

Task outerTask = new Task(() => Console.WriteLine("Outer"));
Task innerTask = outerTask.ContinueWith(t =>
    {
        Thread.Sleep(500);
        Console.WriteLine("Inner");
    }, 
    TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion);
outerTask.Start();
outerTask.Wait();
Console.WriteLine("Outer done");

The output from this code is

Outer
Outer done
Inner

but what I expected/try to achieve is

Outer
Inner
Outer done

Is it possible to use AttachedToParent to block an outer task completion, or is AttachedToParent only effective for nested tasks?

Edit:

What I'm trying to achieve is a that I want to run a continuation task when outerTask is completed successfully. I want outerTask to propagate exceptions from innerTask to the caller, without having to deal with innerTask. If outerTask fails, it should just throw the exception right away (on outerTask.Wait() without calling innerTask).

like image 231
larsmoa Avatar asked Apr 08 '13 14:04

larsmoa


People also ask

What is ContinueWith C#?

The ContinueWith function is a method available on the task that allows executing code after the task has finished execution. In simple words it allows continuation. Things to note here is that ContinueWith also returns one Task. That means you can attach ContinueWith one task returned by this method.

What is a continuation task?

A continuation task (also known just as a continuation) is an asynchronous task that's invoked by another task, known as the antecedent, when the antecedent finishes.

How do I run a task in C#?

To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();


2 Answers

There are no parent-child tasks in your code.
You might want to check what is the inner or child task which can be of two types:

  • detached child task or nested task, i.e. parallel task created withing the delegate of another task without a connection to to the task-creator
  • attached child task or simply child task, in which case If a child task throws an exception that is otherwise unhandled, it is captured by the parent and rethrown

    Update

    "Is it possible to use AttachedToParent to block an outer task completion..."

    "I want to run a continuation task when outerTask is completed successfully"

    CiCiting from the last:

    • "A parent task will not finish executing until all of its child tasks have completed, either normally or with exceptions. The parent essentially performs a Wait command for all of its children
    • If a child task throws an exception that is otherwise unhandled, it is captured by the parent and rethrown. It is possible for many child tasks to throw an exception. All will be combined with any unhandled exception thrown by the parent directly in a single AggregateException."

For your case, in which there are no parent-child tasks, read Handling Exceptions with Continuations:

"It is important to understand that there is no relationship between antecedents and continuations, except for that which controls scheduling. Specifically, exceptions thrown by a task are not propagated to its linked continuation tasks. This means that you should check for exceptions in all of the tasks that you run. The simplest solution is to wait for all of the tasks that may error to complete and surround the Wait method with a Try / Catch block"

There are also the code examples of catching-propagating exceptions in the provided by links articles

Update:

Edit:

What I'm trying to achieve is a that I want to run a continuation task when outerTask is completed successfully. I want outerTask to propagate exceptions from innerTask to the caller, without having to deal with innerTask. If outerTask fails, it should just throw the exception right away (on outerTask.Wait() without calling innerTask).

Probably, you have already seen the code example from MSDN article Task.ContinueWith Method (Func, CancellationToken, TaskContinuationOptions, TaskScheduler), which illustrates how to prevent/follow continuation task if antecedent fails/succedes (or vice versa, 4 combinations). But this is not parent-child, but antecedent-continuation tasks, so there is no containment or linking for exception propagation in either direction.

In case of child-parent tasks, it is impossible to prevent child tasks after they have been already launched and only after that a parent failed (or obviously cancel a parent from child).

like image 177

To achieve what you want, change the line

outerTask.Wait();

to

innerTask.Wait();

as soon as outertask completes, execution passes the Wait and writes 'Outer done' while the inner task is on Thread.Sleep.

like image 32
Steve Avatar answered Sep 28 '22 13:09

Steve