title: async / await and Task.Run -- How to know when everything is done
body: <p>My actual program is more sophisticated than this, but I've tried to simplify things.</p>
  
  <p>So let's say I'm reading a file with a list of URLs. I want to download the HTML from each URL and process it. The processing may be a bit complex, so I'd like it to be done on a separate thread.</p>
  
  <p>The basic problem is how to tell when all the processing is done. For example, if the user tries to close the program before all URLs are processed, I want to give him a message and not exit the program. Alternatively, I want to terminate the program (perhaps with a MsgBox("Done") message) as soon as all the URLs are processed.</p>
  
  <p>I'd like my code to look something as follows (assuming I've got an outer loop reading the URLs and calling this routine)...</p>
  
  <pre><code>List&lt;Task&gt; TaskList = new List&lt;Task&gt;();
  
  async void ProcessSingleUrl(string url) {  
  var web = new HttpClient();  
      var WebPageContents = await web.GetStringAsync(url);  
      Task t = Task.Run(() =&gt; ProcessWebPage(WebPageContents);  
      TaskList.Add(t);
  }
  </code></pre>
  
  <p>The above code should run very quickly (Async methods run pretty well instantly) and return to the caller almost immediately.</p>
  
  <p>But at that point, I may well have no entries whatsoever in TaskList, since a task isn't defined until the GetStringAsync is completed, and none (or maybe just a few) may have finished by then. So </p>
  
  <pre><code>Task.WaitAll(TaskList.ToArray());
  </code></pre>
  
  <p>doesn't work the way I need it to.</p>
  
  <p>If absolutely necessary, I could first read in all the URLs and know how many Tasks to expect, but I'm hoping for a more elegant solution.</p>
  
  <p>I suppose I could increment a counter just before the await, but that feels a bit kludgy.</p>
  
  <p>I assume I'm structuring things incorrectly, but I'm not sure how to reorganize things.</p>
  
  <p>Note: I'm not wedded to Task.Run. Good ol' QueueWorkItem is a possibility, but I think it has pretty well the same problems.</p>