Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the use cases for AttachedToParent?

One of the differences between Task.Run and TaskFactory.StartNew is the addition of the new DenyChildAttach option by default. But AttachedToParent was created for a reason. In what situation would you want to use attached child tasks?

like image 872
BetaKeja Avatar asked Apr 27 '17 20:04

BetaKeja


2 Answers

The use case for AttachedToParent is when you have a nested dynamic task parallelism scenario. That is:

  1. You have an algorithm to execute in parallel (that is, CPU code, not I/O operations), and
  2. The tasks your algorithm must perform vary while the algorithm is running (that is, at the time your algorithm starts, it doesn't know how many tasks it needs), and
  3. There is a hierarchical or parent/child relationship in the completion of these tasks (that is, the "parent" should not be considered complete until all its children are complete, and if any children are failed/canceled, then the parent should be failed/canceled as well, even if its code did not error).

Since the vast majority of concurrency problems are I/O-based (not CPU-based), and since the vast majority of parallelism scenarios are data-based parallelism (not dynamic task parallelism), and since dynamic task parallel problems may or may not have a hierarchical nature, this scenario almost never comes up.

Unfortunately, there is a logical parent/child relationship between tasks (including asynchronous tasks), which have caused a lot of developers to incorrectly attempt to use the AttachedToParent flag with async tasks. Thus, the introduction of the DenyChildAttach flag (which prevents AttachedToParent from taking effect).

like image 88
Stephen Cleary Avatar answered Nov 14 '22 23:11

Stephen Cleary


The only situation I can think of is made obsolete by async-await. E.g. if you want a task to wait on its child tasks you will await them.

var parentTask = Task.Run(async () =>
{
    await Task.Run(() => Thread.Sleep(1000));          
    Console.WriteLine("parent task completed");
});

But in .Net 4.0 you would have to Wait() on them. E.g.

var parentTask = Task.Factory.StartNew(() =>
{
    Task.Factory.StartNew(() => Thread.Sleep(1000)).Wait();       
    Console.WriteLine("parent task completed");
});

Unlike the first example this will block the thread until the child task is complete. With attached tasks we can get the same behaviour like this.

var parentTask = Task.Factory.StartNew(() =>
{
    Task.Factory.StartNew(() => Thread.Sleep(1000), TaskCreationOptions.AttachedToParent)
    .ContinueWith(antecedent => Console.WriteLine("parent task completed", TaskContinuationOptions.AttachedToParent);
});
like image 30
BetaKeja Avatar answered Nov 15 '22 00:11

BetaKeja