{"id":55910,"date":"2010-05-04T18:58:00","date_gmt":"2010-05-04T18:58:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2010\/05\/04\/parallelextensionsextras-tour-15-specialized-task-waiting\/"},"modified":"2010-05-04T18:58:00","modified_gmt":"2010-05-04T18:58:00","slug":"parallelextensionsextras-tour-15-specialized-task-waiting","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/parallelextensionsextras-tour-15-specialized-task-waiting\/","title":{"rendered":"ParallelExtensionsExtras Tour &#8211; #15 &#8211; Specialized Task Waiting"},"content":{"rendered":"<p class=\"MsoNormal\"><em><span><span style=\"font-size: small\">(The full set of ParallelExtensionsExtras Tour posts is available <a href=\"https:\/\/beta.blogs.msdn.com\/pfxteam\/archive\/2010\/04\/04\/9990342.aspx\">here<\/a><\/span><\/span><\/em><span style=\"font-size: small\"><em><span>.)<\/span><\/em><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><em><span><\/span><\/em><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><em><span><\/span><\/em><\/span><span style=\"font-size: small\"><span style=\"font-family: Calibri\">The Task Parallel Library provides the Task.Wait method, which synchronously waits for the target Task to complete.<span>&nbsp; <\/span>If the Task completed successfully, the method simply returns.<span>&nbsp; <\/span>If the Task completed due to an unhandled exception or cancellation, Wait throws an appropriate&nbsp;exception to connote that you can&#8217;t just blindly continue expecting the results or side-effects of the Task to have taken place.<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">While this is a very useful form of waiting, there are others that can be beneficial in certain situations, and <a href=\"https:\/\/code.msdn.microsoft.com\/ParExtSamples\">ParallelExtensionsExtras<\/a> includes a few different forms in the TaskExtrasExtensions.cs file.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><b><span style=\"font-size: small\"><span style=\"font-family: Calibri\">WaitWithPumping<\/p>\n<p><\/span><\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">In a Windows Presentation Foundation application, especially when doing unit testing, you sometimes need to wait for a task on the UI thread.<span>&nbsp; <\/span>However, in doing so you don&rsquo;t want to block the UI thread, and instead you want to continue the WPF message loop, maintaining a responsive application.<span>&nbsp; <\/span>For this purpose, ParallelExtensionsExtras includes the WaitWithPumping extension method for Task.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">public static void WaitWithPumping(this Task task)<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">{<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>if (task == null) throw new ArgumentNullException(&ldquo;task&rdquo;);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>var nestedFrame = new DispatcherFrame();<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>task.ContinueWith(_ =&gt; nestedFrame.Continue = false);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>Dispatcher.PushFrame(nestedFrame);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>task.Wait();<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">}<\/p>\n<p><\/span><\/p>\n<p class=\"Code\">\n<p><span style=\"font-family: Consolas\">&nbsp;<\/span><\/p>\n<\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">WaitWithPumping enters a message loop that will only exit when the task completes, which WPF knows about through a continuation applied to the task.<span>&nbsp; <\/span>Once the message loop has exited, we Wait on the task&nbsp;simply to&nbsp;propagate exceptions&nbsp;in the case where the task did not complete successfully.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">With that in place, you could write WPF code like the following:<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">private void button1_Click(object sender, RoutedEventArgs e)<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">{<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>var t = Task.Factory.StartNew(() =&gt; Thread.Sleep(5000));<\/p>\n<p><\/span><\/p>\n<p class=\"Code\">\n<p><span style=\"font-family: Consolas\">&nbsp;<\/span><\/p>\n<\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>t.WaitWithPumping(); \/\/ UI remains responsive during call<\/p>\n<p><\/span><\/p>\n<p class=\"Code\">\n<p><span style=\"font-family: Consolas\">&nbsp;<\/span><\/p>\n<\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>MessageBox.Show(t.Status.ToString()); \/\/ will show &#8220;RanToCompletion&#8221;<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">}<\/p>\n<p><\/span><\/p>\n<p class=\"Code\">\n<p><span style=\"font-family: Consolas\">&nbsp;<\/span><\/p>\n<\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">Even thought Task <i>t<\/i> won&rsquo;t complete for 5 seconds, and even though WaitWithPumping will block, the UI will still remain responsive.<span>&nbsp; <\/span>Then, because we waited for the Task to complete before exiting the message loop, the MessageBox will show &ldquo;RanToCompletion&rdquo;.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><b><span style=\"font-size: small\"><span style=\"font-family: Calibri\">WaitForCompletionStatus<\/p>\n<p><\/span><\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">Sometimes you want to wait for a Task, but you don&rsquo;t want the Wait operation to throw an exception, even if the target task completed in the Faulted or Canceled states.<span>&nbsp; <\/span>To achieve this, ParallelExtensionsExtras provides the WaitForCompletionStatus extension method on Task:<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">public static TaskStatus WaitForCompletionStatus(this Task task)<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">{<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>if (task == null) throw new ArgumentNullException(&#8220;task&#8221;);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>((IAsyncResult)task).AsyncWaitHandle.WaitOne();<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>return task.Status;<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">}<\/p>\n<p><\/span><\/p>\n<p class=\"Code\">\n<p><span style=\"font-family: Consolas\">&nbsp;<\/span><\/p>\n<\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">This method relies on the fact that Task implements IAsyncResult, and thus implements the AsyncWaitHandle property.<span>&nbsp; <\/span>AsyncWaitHandle returns a WaitHandle that will be set when the task completes, and waiting on this wait handle will not throw exceptions in the same manner as does waiting on the task directly.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">WaitForCompletionStatus returns the final TaskStatus of the task that was waited on.<span>&nbsp; <\/span>This makes it easy to write code that switches on a task&rsquo;s completion state in order to do appropriate follow-up processing, e.g.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">switch(task.WaitForCompletionStatus)<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">{<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>case TaskStatus.RanToCompletion:<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Console.WriteLine(&ldquo;Woo hoo!&rdquo;);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>break;<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>case TaskStatus.Faulted:<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Console.WriteLine(&ldquo;Uh oh: &ldquo; + task.Exception.Message);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>break;<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp; <\/span>case TaskStatus.Canceled:<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Console.WriteLine(&ldquo;Oh well.&rdquo;);<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>break;<\/p>\n<p><\/span><\/p>\n<p class=\"Code\"><span style=\"font-family: Consolas\">}<\/p>\n<p><\/span><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>(The full set of ParallelExtensionsExtras Tour posts is available here.) The Task Parallel Library provides the Task.Wait method, which synchronously waits for the target Task to complete.&nbsp; If the Task completed successfully, the method simply returns.&nbsp; If the Task completed due to an unhandled exception or cancellation, Wait throws an appropriate&nbsp;exception to connote that you [&hellip;]<\/p>\n","protected":false},"author":360,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7907,7909,7924,7912],"class_list":["post-55910","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4","tag-parallel-extensions","tag-parallelextensionsextras","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>(The full set of ParallelExtensionsExtras Tour posts is available here.) The Task Parallel Library provides the Task.Wait method, which synchronously waits for the target Task to complete.&nbsp; If the Task completed successfully, the method simply returns.&nbsp; If the Task completed due to an unhandled exception or cancellation, Wait throws an appropriate&nbsp;exception to connote that you [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55910","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/360"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=55910"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55910\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=55910"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=55910"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=55910"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}