title: Task synchronization without a UI thread
body: <p>In the code below I want to syncronize the reporting of the results of a list of tasks. This is working now because task.Result blocks until the task completes. However, task id = 3 takes a long time to complete and blocks all of the other finished tasks from reporting their status. </p>
  
  <p>I think that I can do this by moving the reporting (Console.Write) into a .ContinueWith instruction but I don't have a UI thread so how do I get a TaskScheduler to syncronize the .ContinueWith tasks?</p>
  
  <p>What I have now:</p>
  
  <pre><code>static void Main(string[] args)
  {
      Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
  
      var tasks = new List&lt;Task&lt;int&gt;&gt;();
  
      for (var i = 0; i &lt; 10; i++)
      {
          var num = i;
          var t = Task&lt;int&gt;.Factory.StartNew(() =&gt;
          {
             if (num == 3)
             {
                 Thread.Sleep(20000);
             }
             Thread.Sleep(new Random(num).Next(1000, 5000));
             Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
             return num;
          });
          tasks.Add(t);
      }
  
      foreach (var task in tasks)
      {
          Console.WriteLine("Completed {0} on {1}", task.Result, Thread.CurrentThread.ManagedThreadId);
      }
  
      Console.WriteLine("End of Main");
      Console.ReadKey();
  }
  </code></pre>
  
  <p>I would like to move to this or something similar but I need the Console.Write("Completed...") to all happen on the same thread:</p>
  
  <pre><code>static void Main(string[] args)
  {
      Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
  
      for (var i = 0; i &lt; 10; i++)
      {
          var num = i;
          Task&lt;int&gt;.Factory.StartNew(() =&gt;
          {
             if (num == 3)
             {
                 Thread.Sleep(20000);
             }
             Thread.Sleep(new Random(num).Next(1000, 10000));
             Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
             return num;
         }).ContinueWith(value =&gt;
         {
             Console.WriteLine("Completed {0} on {1}", value.Result, Thread.CurrentThread.ManagedThreadId);
         } 
  
       /* need syncronization context */);
      }
  
      Console.WriteLine("End of Main");
      Console.ReadKey();
  }
  </code></pre>
  
  <p><strong>-- SOLUTION --</strong> 
  After getting some comments and reading some of the solutions this is the complete solution that does what I want. The goal here is to process severl long running tasks as fast as possible and then do something with the results of each task one at a time.</p>
  
  <pre><code>static void Main(string[] args)
  {
      Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
  
      var results = new BlockingCollection&lt;int&gt;();
  
      Task.Factory.StartNew(() =&gt;
      {
          while (!results.IsCompleted)
          {
              try
              {
                  var x = results.Take();
                  Console.WriteLine("Completed {0} on {1}", x, Thread.CurrentThread.ManagedThreadId);
              }
              catch (InvalidOperationException)
              {
              }
          }
          Console.WriteLine("\r\nNo more items to take.");
      });
  
      var tasks = new List&lt;Task&gt;();
  
      for (var i = 0; i &lt; 10; i++)
      {
          var num = i;
          var t = Task.Factory.StartNew(() =&gt;
          {
              if (num == 3)
              {
                  Thread.Sleep(20000);
              }
              Thread.Sleep(new Random(num).Next(1000, 10000));
              Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
              results.Add(num);
          });
  
          tasks.Add(t);
      }
  
      Task.Factory.ContinueWhenAll(tasks.ToArray(), _ =&gt; results.CompleteAdding());
  
      Console.WriteLine("End of Main");
      Console.ReadKey();
  }
  </code></pre>