How to: Chain Multiple Tasks with Continuations

In the Task Parallel Library, a task whose ContinueWith method is invoked is called the antecedent task and the task that is defined in the ContinueWith method is called the continuation. This example shows how to use the ContinueWith and ContinueWith methods of the Task and Task<TResult> classes to specify a task that starts after its antecedent task finishes.

The example also shows how to specify a continuation that runs only if its antecedent is canceled.

These examples demonstrate how to continue from a single task. You can also create a continuation that runs after any or all of a group of tasks complete or are canceled. For more information, see Task.WhenAll and Task.WhenAny.

The DoSimpleContinuation method shows the basic syntax for ContinueWith. Note that the antecedent task is provided as the input parameter to the lambda expression in the ContinueWith method. This enables you to evaluate the status of the antecedent task before it performs any work in the continuation. Use this simple overload of ContinueWith when you do not have to pass any state from one task to another.

The DoSimpleContinuationWithState method shows how to use ContinueWith to pass the result from the antecedent task to the continuation task.

using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ContinueWith
{
   class Continuations
   {
      static void Main()
      {
         SimpleContinuation();

         Console.WriteLine("Press any key to exit");
         Console.ReadKey();
      }

      static void SimpleContinuation()
      {
         string path = @"C:\users\public\TPLTestFolder\";
         try
         {
            var firstTask = new Task(() => CopyDataIntoTempFolder(path));
            var secondTask = firstTask.ContinueWith((t) => CreateSummaryFile(path));
            firstTask.Start();
         }
         catch (AggregateException e)
         {
            Console.WriteLine(e.Message);
         }
      }

      // A toy function to simulate a workload 
      static void CopyDataIntoTempFolder(string path)
      {
         System.IO.Directory.CreateDirectory(path);
         Random rand = new Random();
         for (int x = 0; x < 50; x++)
         {
            byte[] bytes = new byte[1000];
            rand.NextBytes(bytes);
            string filename = Path.GetRandomFileName();
            string filepath = Path.Combine(path, filename);
            System.IO.File.WriteAllBytes(filepath, bytes);
         }
      }

      static void CreateSummaryFile(string path)
      {
         string[] files = System.IO.Directory.GetFiles(path);
         Parallel.ForEach(files, (file) =>
         {
            Thread.SpinWait(5000);
         });

         System.IO.File.WriteAllText(Path.Combine(path, "__SummaryFile.txt"), "did my work");
         Console.WriteLine("Done with task2");
      }

      static void SimpleContinuationWithState()
      {
         int[] nums = { 19, 17, 21, 4, 13, 8, 12, 7, 3, 5 };
         var f0 = new Task<double>(() => nums.Average());
         var f1 = f0.ContinueWith(t => GetStandardDeviation(nums, t.Result));

         f0.Start();
         Console.WriteLine("the standard deviation is {0}", f1.Result);
      }

      private static double GetStandardDeviation(int[] values, double mean)
      {
         double d = 0.0;
         foreach (var n in values)
         {
            d += Math.Pow(mean - n, 2);
         }
         return Math.Sqrt(d / (values.Length - 1));
      }
   }
}

The type parameter of the Task<TResult> determines the return type of the delegate. That return value is passed to the continuation task. An arbitrary number of tasks can be chained in this manner.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft