5

I will have to create a concurrent software which create several Task, and every Task could generate another task(that could also generate another Task, ...).

I need that the call to the method which launch task is blocking: no return BEFORE all task and subtask are completed.

I know there is this TaskCreationOptions.AttachedToParent property, but I think it will not fit:

The server will have something like 8 cores at least, and each task will create 2-3 subtask, so if I set the AttachedToParent option, I've the impression that the second sub-task will not start before the three tasks of the first subtask ends. So I will have a limited multitasking here.

So with this process tree:

enter image description here

I've the impression that if I set AttachedToParent property everytime I launch a thread, B will not ends before E,F,G are finished, so C will start before B finish, and I will have only 3 actives thread instead of the 8 I can have.

If I don't put the AttachedToParent property, A will be finished very fast and return.

So how could I do to ensure that I've always my 8 cores fully used if I don't set this option?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
J4N
  • 19,480
  • 39
  • 187
  • 340
  • 3
    Don't rely on impressions. Either look it up in the documentation or try it out yourself. – svick Jul 05 '12 at 11:38

3 Answers3

2

The TaskCreationOptions.AttachedToParent does not prevent the other subtasks from starting, but rather prevents the parent task itself from closing. So when E,F and G are started with AttachedToParent, B is not flagged as finished until all three are finished. So it should do just as you want.

The source (in the accepted answer).

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Me.Name
  • 12,259
  • 3
  • 31
  • 48
2

As Me.Name mentioned, AttachedToParent doesn't behave according to your impressions. I think it's a fine option in this case.

But if you don't want to use that for whatever reason, you can wait for all the child tasks to finish with Task.WaitAll(). Although it means you have to have all of them in a collection.

Task.WaitAll() blocks the current thread until all the Tasks are finished. If you don't want that and you are on .Net 4.5, you can use Task.WhenAll(), which will return a single Task that will finish when all of the given Tasks finish.

svick
  • 236,525
  • 50
  • 385
  • 514
1

You could you TaskFactory create options like in this example:

Task parent = new Task(() => { 
var cts = new CancellationTokenSource(); 
var tf = new TaskFactory<Int32>(cts.Token,  
                                        TaskCreationOptions.AttachedToParent,  
                                        TaskContinuationOptions.ExecuteSynchronously,  
TaskScheduler.Default); 

 // This tasks creates and starts 3 child tasks 
 var childTasks = new[] { 
       tf.StartNew(() => Sum(cts.Token, 10000)), 
       tf.StartNew(() => Sum(cts.Token, 20000)), 
       tf.StartNew(() => Sum(cts.Token, Int32.MaxValue))  // Too big, throws Overflow
 }; 

// If any of the child tasks throw, cancel the rest of them 
for (Int32 task = 0; task <childTasks.Length; task++) 
  childTasks[task].ContinueWith( 
     t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted); 

// When all children are done, get the maximum value returned from the  
// non-faulting/canceled tasks. Then pass the maximum value to another  
// task which displays the maximum result 
tf.ContinueWhenAll( 
   childTasks,  
   completedTasks => completedTasks.Where( 
     t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result), CancellationToken.None) 
   .ContinueWith(t =>Console.WriteLine("The maximum is: " + t.Result), 
      TaskContinuationOptions.ExecuteSynchronously); 
}); 

// When the children are done, show any unhandled exceptions too 
parent.ContinueWith(p => { 
    // I put all this text in a StringBuilder and call Console.WriteLine just once  
    // because this task could execute concurrently with the task above & I don't  
    // want the tasks' output interspersed 
    StringBuildersb = new StringBuilder( 
                      "The following exception(s) occurred:" + Environment.NewLine); 

    foreach (var e in p.Exception.Flatten().InnerExceptions)  
         sb.AppendLine("   "+ e.GetType().ToString()); 

    Console.WriteLine(sb.ToString()); 
  }, TaskContinuationOptions.OnlyOnFaulted);

  // Start the parent Task so it can start its children 
  parent.Start();
Alex F
  • 3,180
  • 2
  • 28
  • 40