{"id":503,"date":"2012-01-21T16:49:00","date_gmt":"2012-01-21T16:49:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2012\/01\/21\/await-synchronizationcontext-and-console-apps-part-2\/"},"modified":"2012-01-21T16:49:00","modified_gmt":"2012-01-21T16:49:00","slug":"await-synchronizationcontext-and-console-apps-part-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/await-synchronizationcontext-and-console-apps-part-2\/","title":{"rendered":"Await, SynchronizationContext, and Console Apps: Part 2"},"content":{"rendered":"<p>Yesterday, I <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/01\/20\/10259049.aspx\">blogged<\/a> about how you can implement a custom SynchronizationContext in order to pump the continuations used by async methods so that they may be processed on a single, dedicated thread.&nbsp; I also highlighted that this is basically what UI frameworks like Windows Forms and Windows Presentation Foundation do with their message pumps.<\/p>\n<p>Now that we understand the mechanics of how these things work, it&rsquo;s worth pointing out that we can achieve the same basic semantics without writing our own custom SynchronizationContext.&nbsp; Instead, we can use one that already exists in the .NET Framework: DispatcherSynchronizationContext.&nbsp; Through its Dispatcher class and its <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.threading.dispatcher.pushframe.aspx\">PushFrame<\/a> method, WPF provides the ability to (as described in MSDN) &ldquo;enter an execute loop&rdquo; that &ldquo;processes pending work items.&rdquo;&nbsp; This is exactly what our custom SynchronizationContext was doing with its usage of BlockingCollection&lt;T&gt;, so we can just use WPF&rsquo;s support instead of developing our own. (You might ask then why I started by describing how to do it manually and writing my own to exemplify it.&nbsp; I do so because I think it&rsquo;s important to really understand how things work; I typically find that developers write better higher-level code if they have the right mental model for what&rsquo;s happening under the covers, allowing them to better reason about bugs, about performance, about reliability, and the like.)<\/p>\n<p>Below you can see how few lines of code it takes to achieve this support.&nbsp; (To compile this code, you&rsquo;ll need to reference WindowsBase.dll to bring in the relevant WPF types.)<\/p>\n<blockquote>\n<p><span style=\"font-family: Consolas;font-size: x-small\"><span style=\"color: #0000ff\">using<\/span> System; <br><span style=\"font-family: Consolas;font-size: x-small\"><span style=\"color: #0000ff\">using<\/span> <\/span>System.Threading; <br><span style=\"font-family: Consolas;font-size: x-small\"><span style=\"color: #0000ff\">using<\/span> <\/span>System.Threading.Tasks; <br><span style=\"font-family: Consolas;font-size: x-small\"><span style=\"color: #0000ff\">using<\/span> <\/span>System.Windows.Threading; <\/p>\n<p><span style=\"color: #0000ff\">public static class<\/span> <span style=\"color: #4bacc6\">AsyncPump<\/span> <br>{ <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public static void<\/span> Run(<span style=\"color: #4bacc6\">Func<\/span>&lt;<span style=\"color: #4bacc6\">Task<\/span>&gt; func) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">if<\/span> (func == <span style=\"color: #0000ff\">null<\/span>) <span style=\"color: #0000ff\">throw new<\/span> <span style=\"color: #4bacc6\">ArgumentNullException<\/span>(<span style=\"color: #c0504d\">&#8220;func&#8221;<\/span>); <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> prevCtx = <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.Current; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">try<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> syncCtx = <span style=\"color: #0000ff\">new<\/span> <span style=\"color: #4bacc6\">DispatcherSynchronizationContext<\/span>(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.SetSynchronizationContext(syncCtx); <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> t = func(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (t == <span style=\"color: #0000ff\">null<\/span>) <span style=\"color: #0000ff\">throw new <\/span><span style=\"color: #4bacc6\">InvalidOperationException<\/span>(); <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var <\/span>frame = <span style=\"color: #0000ff\">new <\/span><span style=\"color: #4bacc6\">DispatcherFrame<\/span>(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.ContinueWith(_ =&gt; { frame.Continue = <span style=\"color: #0000ff\">false<\/span>; }, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">TaskScheduler<\/span>.Default); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Dispatcher<\/span>.PushFrame(frame); <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.GetAwaiter().GetResult(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">finally<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.SetSynchronizationContext(prevCtx); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp; } <br>}<\/span><\/p>\n<\/blockquote>\n<p>In short, we instantiate a DispatcherSynchronizationContext and publish it to be Current on the current thread; this is what enables the awaits inside of the async method being processed to queue their continuations back to this thread and this thread&rsquo;s Dispatcher.&nbsp; Then we instantiate a DispatcherFrame, which represents an execute loop for WPF&rsquo;s message pump.&nbsp; We use a continuation to signal to that DispatcherFrame when it should exit its loop (i.e. when the Task completes).&nbsp; And then we start the frame&rsquo;s execute loop via the PushFrame method.<\/p>\n<p>All in all, just a few lines of code to achieve some powerful and useful behavior.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yesterday, I blogged about how you can implement a custom SynchronizationContext in order to pump the continuations used by async methods so that they may be processed on a single, dedicated thread.&nbsp; I also highlighted that this is basically what UI frameworks like Windows Forms and Windows Presentation Foundation do with their message pumps. Now [&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,7925,36,7909,7912],"class_list":["post-503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4","tag-net-4-5","tag-async","tag-parallel-extensions","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>Yesterday, I blogged about how you can implement a custom SynchronizationContext in order to pump the continuations used by async methods so that they may be processed on a single, dedicated thread.&nbsp; I also highlighted that this is basically what UI frameworks like Windows Forms and Windows Presentation Foundation do with their message pumps. Now [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/503","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=503"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/503\/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=503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}