{"id":56021,"date":"2012-02-11T21:37:30","date_gmt":"2012-02-11T21:37:30","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2012\/02\/11\/building-async-coordination-primitives-part-3-asynccountdownevent\/"},"modified":"2012-02-11T21:37:30","modified_gmt":"2012-02-11T21:37:30","slug":"building-async-coordination-primitives-part-3-asynccountdownevent","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/building-async-coordination-primitives-part-3-asynccountdownevent\/","title":{"rendered":"Building Async Coordination Primitives, Part 3: AsyncCountdownEvent"},"content":{"rendered":"<p>In my last two posts, I discussed building <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/11\/10266920.aspx\">AsyncManualResetEvent<\/a> and <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/11\/10266923.aspx\">AsyncAutoResetEvent<\/a> coordination primitives.&nbsp; In this post, I&rsquo;ll build on that to create a simple AsyncCountdownEvent.<\/p>\n<p>A countdown event is an event that will allow waiters to complete after receiving a particular number of signals.&nbsp; The &ldquo;countdown&rdquo; comes from the common fork\/join pattern in which it&rsquo;s often utilized: a certain number of operations participate, and as they complete they signal the event, which counts down from the original number to 0.&nbsp; When it gets to 0, it becomes set, and all waiters can complete.<\/p>\n<p>The shape of our type will be as follows:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public class<\/font> <font color=\"#4bacc6\">AsyncCountdownEvent<\/font>         <br>{         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public<\/font> AsyncCountdownEvent(<font color=\"#0000ff\">int<\/font> initialCount);         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public<\/font> <font color=\"#4bacc6\">Task<\/font> WaitAsync();         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public void <\/font>Signal();         <br>}<\/font><\/p>\n<\/blockquote>\n<p>At its core, a countdown event is really just a manual reset event and an integral count, so our AsyncCountdownEvent will have two members:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">private readonly<\/font> <font color=\"#4bacc6\">AsyncManualResetEvent<\/font> m_amre = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">AsyncManualResetEvent<\/font>();         <br><font color=\"#0000ff\">private int<\/font> m_count;<\/font>       <br><\/p>\n<\/blockquote>\n<p>The constructor of our type simply initializes m_count based on a supplied number of signals:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public<\/font> AsyncCountdownEvent(<font color=\"#0000ff\">int<\/font> initialCount)         <br>{         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (initialCount &lt;= 0) <font color=\"#0000ff\">throw new<\/font> <font color=\"#4bacc6\">ArgumentOutOfRangeException<\/font>(<font color=\"#c0504d\">&#8220;initialCount&#8221;<\/font>);         <br>&nbsp;&nbsp;&nbsp; m_count = initialCount;         <br>}<\/font><\/p>\n<\/blockquote>\n<p>The WaitAsync method is then trivial, as it&rsquo;ll just delegate to the corresponding method on the AsyncManualResetEvent:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public<\/font> <font color=\"#4bacc6\">Task<\/font> WaitAsync() { <font color=\"#0000ff\">return<\/font> m_amre.WaitAsync(); }<\/font><\/p>\n<\/blockquote>\n<p>Finally, our Signal method will decrement m_count, and if that brings it to 0, we&rsquo;ll Set the m_amre:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public void <\/font>Signal()         <br>{         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (m_count &lt;= 0)         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">throw new<\/font> <font color=\"#4bacc6\">InvalidOperationException<\/font>();         <\/p>\n<p><\/font><font size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">int<\/font> newCount = <font color=\"#4bacc6\">Interlocked<\/font>.Decrement(<font color=\"#0000ff\">ref<\/font> m_count);         <br><\/font><font size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (newCount == 0)         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_amre.Set();         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">else if<\/font> (newCount &lt; 0)         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">throw new<\/font> <font color=\"#4bacc6\">InvalidOperationException<\/font>();         <br>}<\/font><\/p>\n<\/blockquote>\n<p>One common usage of a type like AsyncCountdownEvent is using it as a form of a barrier: all participants signal and then wait for all of the other participants to arrive.&nbsp; Given that, we could also add a simple SignalAndWait method to implement this common pattern:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public<\/font> <font color=\"#4bacc6\">Task<\/font> SignalAndWait()         <br>{         <br>&nbsp;&nbsp;&nbsp; Signal();         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">return<\/font> WaitAsync();         <br>}<\/font><\/p>\n<\/blockquote>\n<p>Next time, we&rsquo;ll take a look at implementing an actual <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/11\/10266932.aspx\">asynchronous barrier<\/a>, one that can be used over and over by the participants to operate in lock step.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my last two posts, I discussed building AsyncManualResetEvent and AsyncAutoResetEvent coordination primitives.&nbsp; In this post, I&rsquo;ll build on that to create a simple AsyncCountdownEvent. A countdown event is an event that will allow waiters to complete after receiving a particular number of signals.&nbsp; The &ldquo;countdown&rdquo; comes from the common fork\/join pattern in which it&rsquo;s [&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,7916,7909,7912],"class_list":["post-56021","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4-5","tag-coordination-data-structures","tag-parallel-extensions","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>In my last two posts, I discussed building AsyncManualResetEvent and AsyncAutoResetEvent coordination primitives.&nbsp; In this post, I&rsquo;ll build on that to create a simple AsyncCountdownEvent. A countdown event is an event that will allow waiters to complete after receiving a particular number of signals.&nbsp; The &ldquo;countdown&rdquo; comes from the common fork\/join pattern in which it&rsquo;s [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56021","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=56021"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56021\/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=56021"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56021"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56021"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}