{"id":56028,"date":"2012-02-02T22:46:00","date_gmt":"2012-02-02T22:46:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2012\/02\/02\/await-synchronizationcontext-and-console-apps-part-3\/"},"modified":"2012-02-02T22:46:00","modified_gmt":"2012-02-02T22:46:00","slug":"await-synchronizationcontext-and-console-apps-part-3","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/await-synchronizationcontext-and-console-apps-part-3\/","title":{"rendered":"Await, SynchronizationContext, and Console Apps: Part 3"},"content":{"rendered":"<p>In <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/01\/20\/10259049.aspx\">Part 1<\/a> and <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/01\/21\/10259307.aspx\">Part 2<\/a> of this short series, I demonstrated how you can build a SynchronizationContext and use it run an async method such that all of the continuations in that method will run on serialized on the current thread.&nbsp; This can be helpful when executing async methods in a console app, or in a unit test framework that doesn&rsquo;t directly support async methods.&nbsp; However, the support I showed thus far targets async methods that return Task&hellip; what about async methods that return void?<\/p>\n<p>C# and Visual Basic support two flavors of async methods: ones that return tasks (either Task or Task&lt;T&gt;) and ones that return void.&nbsp; The former use the returned Task to represent the completion of the async method. In the case of an &ldquo;async void&rdquo; method, however, there is no returned Task to represent the method&rsquo;s processing.&nbsp; Instead, &ldquo;async void&rdquo; methods interact with the current SynchronizationContext to alert the context to the async method&rsquo;s execution status.&nbsp; Before entering the body of the async method, if there is a current SynchronizationContext, it is retrieved and its OperationStarted method is called.&nbsp; And after the async method has completed, that same context has its OperationCompleted method called.&nbsp; Further, if an exception goes unhandled in the body of the async void method, the throwing of that exception is Post to the SynchronizationContext, so that the exception escapes back to the context for it to handle as it pleases.<\/p>\n<p>All of this means that if we want our AsyncPump to be able to handle &ldquo;async void&rdquo; methods in addition to &ldquo;async Task&rdquo; methods, we need to augment the type slightly.&nbsp; First, we need to augment our SingleThreadSynchronizationContext to react appropriate to calls to OperationStarted and OperationCompleted.&nbsp; These methods need to maintain a count of how many outstanding operations there are, such that when the count reaches 0, we call Complete, just as <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/01\/20\/10259049.aspx\">before<\/a> we called Complete when the async method&rsquo;s Task completed.&nbsp; We do this by adding three members to the custom context:<\/p>\n<blockquote>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">private<\/span> <span style=\"color: #0000ff\">int<\/span><span style=\"color: #333333\"> m_<\/span>operationCount = 0;<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">public override void<\/span> OperationStarted() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Interlocked<\/span>.Increment(<span style=\"color: #0000ff\">ref<\/span> m_operationCount); <br \/>} <\/p>\n<p><span style=\"color: #0000ff\">public override void<\/span> OperationCompleted() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">if<\/span> (<span style=\"color: #4bacc6\">Interlocked<\/span>.Decrement(<span style=\"color: #0000ff\">ref<\/span> m_operationCount) == 0) <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Complete(); <br \/>}<\/span><\/span><\/p>\n<\/blockquote>\n<p>Then we need to add a new AsyncPump.Run overload that works with Action (for &ldquo;async void&rdquo; methods) instead of with Func&lt;Task&gt; (for &ldquo;async Task&rdquo; methods). As a reminder, here&rsquo;s the existing Run method from our AsyncPump class:<\/p>\n<blockquote>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">public static void<\/span> Run(<span style=\"color: #4bacc6\">Func<\/span>&lt;<span style=\"color: #4bacc6\">Task<\/span>&gt; asyncMethod) <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> prevCtx = <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.Current; <br \/>&nbsp;&nbsp;&nbsp; <\/span><\/span><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">try <br \/><\/span>&nbsp;&nbsp;&nbsp; { <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> syncCtx = <span style=\"color: #0000ff\">new<\/span> <span style=\"color: #4bacc6\">SingleThreadSynchronizationContext<\/span>(<span style=\"color: #0000ff\">false<\/span>); <br \/>&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; <span style=\"color: #0000ff\">var<\/span> t = asyncMethod(); <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.ContinueWith(delegate { syncCtx.Complete(); }, <span style=\"color: #4bacc6\">TaskScheduler<\/span>.Default); <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; syncCtx.RunOnCurrentThread(); <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.GetAwaiter().GetResult(); <br \/>&nbsp;&nbsp;&nbsp; } <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">finally<\/span> <br \/>&nbsp;&nbsp;&nbsp; { <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.SetSynchronizationContext(prevCtx); <br \/>&nbsp;&nbsp;&nbsp; } <br \/>}<\/span><\/span><\/p>\n<\/blockquote>\n<p>Most of this will remain the same for our new Action-based variant.&nbsp; In fact, for the new one, we primarily just need to delete all the code having to do with the returned task, since there isn&rsquo;t one, and all notion of completion is being handled by the OperationStarted and OperationCompleted methods we added to the context.&nbsp; We do surround the asyncMethod invocation with calls to OperationStarted and OperationCompleted, just in case the asyncMethod is actually just a void method and not an &ldquo;async void&rdquo; method, in which case we need to make sure the operation count is greater than 0 for the duration of the invocation in order to avoid races that could result if the delegate invoked other async void methods.<\/p>\n<blockquote>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">public static void<\/span> Run(<span style=\"color: #4bacc6\">Action<\/span> asyncMethod) <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> prevCtx = <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.Current; <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">try<\/span> <br \/>&nbsp;&nbsp;&nbsp; { <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> syncCtx = <span style=\"color: #0000ff\">new<\/span> <span style=\"color: #4bacc6\">SingleThreadSynchronizationContext<\/span>(<span style=\"color: #0000ff\">true<\/span>); <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.SetSynchronizationContext(syncCtx); <\/p>\n<p><\/span><\/span><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; syncCtx.OperationStarted(); <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asyncMethod(); <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; syncCtx.OperationCompleted();<\/strong> <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; syncCtx.RunOnCurrentThread(); <br \/>&nbsp;&nbsp;&nbsp; } <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">finally<\/span> <br \/>&nbsp;&nbsp;&nbsp; { <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">SynchronizationContext<\/span>.SetSynchronizationContext(prevCtx); <br \/>&nbsp;&nbsp;&nbsp; } <br \/>}<\/span><\/span><\/p>\n<\/blockquote>\n<p>That&rsquo;s it (note that I&#8217;ve added a parameter to SingleThreadSynchronizationContext&#8217;s constructor, which allows me to specify whether operation count tracking should be performed: we want it for this new Run method, but not for the previously described ones). We&rsquo;re now able to use our AsyncPump to run &ldquo;async void&rdquo; methods synchronously with all continuations executed on the current thread, e.g.<\/p>\n<blockquote>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">static void<\/span> Main() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">AsyncPump<\/span>.Run((<span style=\"color: #4bacc6\">Action<\/span>)FooAsync); <br \/>}<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">static async void<\/span> FooAsync() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; Foo1Async(); <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">await<\/span> Foo2Async(); <br \/>&nbsp;&nbsp;&nbsp; Foo3Async(); <br \/>}<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">static async void<\/span> Foo1Async() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">await<\/span> <span style=\"color: #4bacc6\">Task<\/span>.Delay(1000); <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Console<\/span>.WriteLine(1); <br \/>}<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">static async<\/span> <span style=\"color: #4bacc6\">Task<\/span> Foo2Async() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">await<\/span> <span style=\"color: #4bacc6\">Task<\/span>.Delay(1000); <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Console<\/span>.WriteLine(2); <br \/>}<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas\"><span style=\"font-size: x-small\"><span style=\"color: #0000ff\">static async void<\/span> Foo3Async() <br \/>{ <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">await<\/span> <span style=\"color: #4bacc6\">Task<\/span>.Delay(1000); <br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Console<\/span>.WriteLine(3); <br \/>}<\/span><\/span><\/p>\n<\/blockquote>\n<p>Happy async&rsquo;ing.<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Components.PostAttachments\/00\/10\/26\/35\/55\/AsyncPump.cs\">AsyncPump.cs<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Part 1 and Part 2 of this short series, I demonstrated how you can build a SynchronizationContext and use it run an async method such that all of the continuations in that method will run on serialized on the current thread.&nbsp; This can be helpful when executing async methods in a console app, or [&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":[7925,36,7909],"class_list":["post-56028","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4-5","tag-async","tag-parallel-extensions"],"acf":[],"blog_post_summary":"<p>In Part 1 and Part 2 of this short series, I demonstrated how you can build a SynchronizationContext and use it run an async method such that all of the continuations in that method will run on serialized on the current thread.&nbsp; This can be helpful when executing async methods in a console app, or [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56028","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=56028"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56028\/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=56028"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56028"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56028"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}