{"id":56020,"date":"2012-02-11T22:59:30","date_gmt":"2012-02-11T22:59:30","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2012\/02\/11\/building-async-coordination-primitives-part-4-asyncbarrier\/"},"modified":"2012-02-11T22:59:30","modified_gmt":"2012-02-11T22:59:30","slug":"building-async-coordination-primitives-part-4-asyncbarrier","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/building-async-coordination-primitives-part-4-asyncbarrier\/","title":{"rendered":"Building Async Coordination Primitives, Part 4: AsyncBarrier"},"content":{"rendered":"<p>Last time, we looked at building an <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/11\/10266930.aspx\">AsyncCountdownEvent<\/a>.&nbsp; At the end of the post, I highlighted a common pattern for using such a type, which is for all of the participants to signal and then wait for all of the other participants to signal as well.&nbsp; This kind of synchronization is typically referred to as a &ldquo;barrier,&rdquo; and often it can be used in a round.&nbsp; Each participant will do some work, then signal-and-wait for the barrier, then do the next round of work, then signal-and-wait for the barrier, and so on.<\/p>\n<p>Just as we built an AsyncCountdownEvent, we can easily build an AsyncBarrier.&nbsp; Here&rsquo;s the shape of our type:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public class<\/font> <font color=\"#4bacc6\">AsyncBarrier<\/font>         <br>{         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public<\/font> AsyncBarrier(<font color=\"#0000ff\">int<\/font> participantCount);         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public<\/font> <font color=\"#4bacc6\">Task<\/font> SignalAndWait();         <br>}<\/font><\/p>\n<\/blockquote>\n<p>To start, we need a few members.&nbsp; As with AsyncCountdown, we need to know how many participants there are.&nbsp; However, with AsyncCountdownEvent we didn&rsquo;t need to store that number permanently&hellip; we only needed to know how many signals were remaining.&nbsp; With AsyncBarrier, every time we get down to 0, we&rsquo;ll need to reset back to the original number of participants, so we need to store both the participant count and the remaining number of participants that still need to signal.&nbsp; We also need a TaskCompletionSource&lt;bool&gt; to create the task that all of the participants will wait on.<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">private readonly int<\/font> m_participantCount;         <br><font color=\"#0000ff\">private<\/font> <font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt; m_tcs = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt;();         <br><font color=\"#0000ff\">private<\/font> <font color=\"#0000ff\">int<\/font> m_remainingParticipants;<\/font><\/p>\n<\/blockquote>\n<p>Our constructor will simply initialize the counts based on the user-supplied number of participants we expect:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public<\/font> AsyncBarrier(<font color=\"#0000ff\">int<\/font> participantCount)         <br>{         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (participantCount &lt;= 0) <font color=\"#0000ff\">throw new<\/font> <font color=\"#4bacc6\">ArgumentOutOfRangeException<\/font>(<font color=\"#c0504d\">&#8220;participantCount&#8221;<\/font>);         <br>&nbsp;&nbsp;&nbsp; m_remainingParticipants = m_participantCount = participantCount;         <br>}<\/font>       <br><\/p>\n<\/blockquote>\n<p>Finally, our SignalAndWait method is very similar to that of AsyncCountdown, in that we decrement the number of remaining participants, and when the count reaches 0, we complete the TaskCompletionSource&lt;bool&gt;.&nbsp; However, here we need to be careful about the order in which we do that.&nbsp; Once a participant wakes up from waiting, they are likely to do the work for their next round of processing and then signal-and-wait on the barrier again, which means that by that time it needs to have already been reconfigured for the next round.&nbsp; That means that after our count hits 0 but before we complete the task so as to wake the waiters, we need to reset the remaining count back up to the participant count, and we need to swap in a new TaskCompletionSource&lt;bool&gt; to be used for the next round (this example class does not handle the more difficult error case where more participants than excepted join the fray):<\/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; <font color=\"#0000ff\">var<\/font> tcs = m_tcs;         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (<font color=\"#4bacc6\">Interlocked<\/font>.Decrement(<font color=\"#0000ff\">ref<\/font> m_remainingParticipants) == 0)         <br>&nbsp;&nbsp;&nbsp; {         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_remainingParticipants = m_participantCount;         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_tcs = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt;();         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tcs.SetResult(<font color=\"#0000ff\">true<\/font>);         <br>&nbsp;&nbsp;&nbsp; }         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">return<\/font> tcs.Task;         <br>}<\/font><\/p>\n<\/blockquote>\n<p>That&rsquo;s it.&nbsp; Of course, there are other ways we could implement this.&nbsp; One potential problem with the above design could arise if all of the participants chose to use synchronous continuations, as the continuations would then all end up getting serialized.&nbsp; Dealing with that could just be left up to the participants, or we could help them by implementing this so that each participant got their own Task, with us completing each task in parallel.&nbsp; That might look instead like the following:<\/p>\n<blockquote>\n<p><font size=\"2\" face=\"Consolas\"><font color=\"#0000ff\">public class<\/font> AsyncBarrier         <br>{         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">private readonly int<\/font> m_participantCount;         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">private int<\/font> m_remainingParticipants;         <br>&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">private<\/font> <font color=\"#4bacc6\">ConcurrentStack<\/font>&lt;<font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt;&gt; m_waiters;<\/font><\/p>\n<p><font size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public<\/font> AsyncBarrier(<font color=\"#0000ff\">int<\/font> participantCount)         <br>&nbsp;&nbsp;&nbsp; {         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (participantCount &lt;= 0) <font color=\"#0000ff\">throw new<\/font> <font color=\"#4bacc6\">ArgumentOutOfRangeException<\/font>(<font color=\"#c0504d\">&#8220;participantCount&#8221;<\/font>);         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_remainingParticipants = m_participantCount = participantCount;         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_waiters = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">ConcurrentStack<\/font>&lt;<font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt;&gt;();         <br>&nbsp;&nbsp;&nbsp; }<\/font><\/p>\n<p><font size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">public<\/font> <font color=\"#4bacc6\">Task<\/font> SignalAndWait()         <br>&nbsp;&nbsp;&nbsp; {         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">var<\/font> tcs = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt;();         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_waiters.Push(tcs);         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">if<\/font> (<font color=\"#4bacc6\">Interlocked<\/font>.Decrement(<font color=\"#0000ff\">ref<\/font> m_remainingParticipants) == 0)         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_remainingParticipants = m_participantCount;         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">var<\/font> waiters = m_waiters;         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_waiters = <font color=\"#0000ff\">new<\/font> <font color=\"#4bacc6\">ConcurrentStack<\/font>&lt;<font color=\"#4bacc6\">TaskCompletionSource<\/font>&lt;<font color=\"#0000ff\">bool<\/font>&gt;&gt;();         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#4bacc6\">Parallel<\/font>.ForEach(waiters, w =&gt; w.SetResult(<font color=\"#0000ff\">true<\/font>));         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=\"#0000ff\">return<\/font> tcs.Task;         <br>&nbsp;&nbsp;&nbsp; }         <br>}<\/font><\/p>\n<\/blockquote>\n<p>Next time, we&rsquo;ll look at building an <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/12\/10266983.aspx\">asynchronous semaphore<\/a>.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time, we looked at building an AsyncCountdownEvent.&nbsp; At the end of the post, I highlighted a common pattern for using such a type, which is for all of the participants to signal and then wait for all of the other participants to signal as well.&nbsp; This kind of synchronization is typically referred to as [&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,7916,7909,7912],"class_list":["post-56020","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4-5","tag-async","tag-coordination-data-structures","tag-parallel-extensions","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>Last time, we looked at building an AsyncCountdownEvent.&nbsp; At the end of the post, I highlighted a common pattern for using such a type, which is for all of the participants to signal and then wait for all of the other participants to signal as well.&nbsp; This kind of synchronization is typically referred to as [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56020","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=56020"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56020\/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=56020"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56020"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56020"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}