{"id":423,"date":"2012-02-11T19:17:00","date_gmt":"2012-02-11T19:17:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2012\/02\/11\/building-async-coordination-primitives-part-1-asyncmanualresetevent\/"},"modified":"2012-02-11T19:17:00","modified_gmt":"2012-02-11T19:17:00","slug":"building-async-coordination-primitives-part-1-asyncmanualresetevent","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/building-async-coordination-primitives-part-1-asyncmanualresetevent\/","title":{"rendered":"Building Async Coordination Primitives, Part 1: AsyncManualResetEvent"},"content":{"rendered":"<p>The <a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkId=204847\">Task-based Async Pattern<\/a> (TAP) isn&rsquo;t just about asynchronous operations that you initiate and then asynchronously wait for to complete.&nbsp; More generally, tasks can be used to represent all sorts of happenings, enabling you to await for any matter of condition to occur.&nbsp; We can even use Tasks to build simple coordination primitives like their synchronous counterparts but that allow the waiting to be done asynchronously.<\/p>\n<p>One of the more basic coordination primitives is an event, and there are a few of these in the .NET Framework. ManualResetEvent and AutoResetEvent wrap their Win32 counterparts, and then more recently .NET 4 saw the addition of ManualResetEventSlim, which is a lighter-weight version of ManualResetEvent.&nbsp; An event is something that one party can wait on for another party to signal.&nbsp; In the case of a manual-reset event, the event remains signaled after it&rsquo;s been set and until it&rsquo;s explicitly reset; until it is reset, all waits on the event succeed.<\/p>\n<p>TaskCompletionSource&lt;TResult&gt; is itself a form of an event, just one without a reset. It starts in the non-signaled state; its Task hasn&rsquo;t been completed, and thus all waits on the Task won&rsquo;t complete until the Task is completed.&nbsp; Then the {Try}Set* methods act as a signal, moving the Task into the completed state, such that all waits complete.&nbsp; Thus, we can easily build an AsyncManualResetEvent on top of TaskCompletionSource&lt;TResult&gt;; the only behavior we&rsquo;re really missing is the &ldquo;reset&rdquo; capability, which we&rsquo;ll provide by swapping in a new TaskCompletionSource&lt;TResult&gt; instance.<\/p>\n<p>Here&rsquo;s the shape of the type we&rsquo;re aiming to build:<\/p>\n<blockquote>\n<p><span style=\"font-family: consolas;font-size: x-small\"><font size=\"2\"><span style=\"color: #0000ff\">public class<\/span> <span style=\"color: #4bacc6\">AsyncManualResetEvent<\/span>           <br>{           <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #4bacc6\">Task<\/span> WaitAsync();           <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">void<\/span> Set();           <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public void<\/span> Reset();           <br>}<\/font><\/span><\/p>\n<\/blockquote>\n<p>WaitAsync and Set are both easy.&nbsp; Wrapping a TaskCompletionSource&lt;bool&gt;, Set will complete the TaskCompletionSource&lt;bool&gt; with TrySetResult, and WaitAsync will return the completion source&rsquo;s Task:<\/p>\n<blockquote>\n<p><span style=\"font-family: consolas;font-size: x-small\"><font size=\"2\"><span style=\"color: #0000ff\">public class<\/span> <span style=\"color: #4bacc6\">AsyncManualResetEvent<\/span>           <br>{           <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">private volatile<\/span> <span style=\"color: #4bacc6\">TaskCompletionSource<\/span>&lt;<span style=\"color: #0000ff\">bool<\/span>&gt; m_tcs = <span style=\"color: #0000ff\">new<\/span> <span style=\"color: #4bacc6\">TaskCompletionSource<\/span>&lt;<span style=\"color: #0000ff\">bool<\/span>&gt;();           <\/p>\n<p>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #4bacc6\">Task<\/span> WaitAsync() { <span style=\"color: #0000ff\">return<\/span> m_tcs.Task; }           <\/p>\n<p>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public void<\/span> Set() { m_tcs.TrySetResult(<span style=\"color: #0000ff\">true<\/span>); }           <\/p>\n<p>&nbsp;&nbsp;&nbsp; &hellip;           <br>}<\/font><\/span><\/p>\n<\/blockquote>\n<p>That leaves just the Reset method.&nbsp; Our goal for Reset is to make the Tasks returned from subsequent calls to WaitAsync not completed, and since Tasks never transition from completed to not-completed, we need to swap in a new TaskCompletionSource&lt;bool&gt;.&nbsp; In doing so, though, we need to make sure that, if multiple threads are calling Reset, Set, and WaitAsync concurrently, no Tasks returned from WaitAsync are orphaned (meaning that we wouldn&rsquo;t want someone to call WaitAsync and get back a Task that won&rsquo;t be completed the next time someone calls Set).&nbsp; To achieve that, we&rsquo;ll make sure to only swap in a new Task if the current one is already completed, and we&rsquo;ll make sure that we do the swap atomically. (There are of course other policies that would be valid here; this is simply the one I&rsquo;ve chosen for this particular example.)<\/p>\n<blockquote><p><span style=\"font-family: consolas;font-size: x-small\"><font size=\"2\"><span style=\"color: #0000ff\">public class<\/span> <span style=\"color: #4bacc6\">AsyncManualResetEvent<\/span>         <br>{         <br><span style=\"color: #0000ff\">&nbsp;&nbsp;&nbsp; private volatile<\/span> <span style=\"color: #4bacc6\">TaskCompletionSource<\/span>&lt;<span style=\"color: #0000ff\">bool<\/span>&gt; m_tcs = <span style=\"color: #0000ff\">new<\/span> <span style=\"color: #4bacc6\">TaskCompletionSource<\/span>&lt;<span style=\"color: #0000ff\">bool<\/span>&gt;();         <\/p>\n<p><span style=\"color: #0000ff\">&nbsp;&nbsp;&nbsp; public<\/span> <span style=\"color: #4bacc6\">Task<\/span> WaitAsync() { <span style=\"color: #0000ff\">return<\/span> m_tcs.Task; }         <\/p>\n<p><span style=\"color: #0000ff\">&nbsp;&nbsp;&nbsp; public void<\/span> Set() { m_tcs.TrySetResult(<span style=\"color: #0000ff\">true<\/span>); }         <br><\/font><\/span><span style=\"font-family: consolas;font-size: x-small\">     <br><font size=\"2\">&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">public void<\/span> Reset()         <br>&nbsp;&nbsp;&nbsp; {         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">while<\/span> (<span style=\"color: #0000ff\">true<\/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> tcs = m_tcs;         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">if<\/span> (!tcs.Task.IsCompleted ||         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Interlocked<\/span>.CompareExchange(<span style=\"color: #0000ff\">ref<\/span> m_tcs, <span style=\"color: #0000ff\">new<\/span> <span style=\"color: #4bacc6\">TaskCompletionSource<\/span>&lt;<span style=\"color: #0000ff\">bool<\/span>&gt;(), tcs) == tcs)         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">return<\/span>;         <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }         <br>&nbsp;&nbsp;&nbsp; }         <br>}<\/font><\/span><\/p><\/blockquote>\n<p>With that, our type is done.&nbsp; However, there is one more potentially important behavior to keep in mind.&nbsp; In previous posts, I&rsquo;ve talked about continuations and how they can be made to execute synchronously, meaning that the continuation will execute as part of the task&rsquo;s completion, synchronously on the same thread that&rsquo;s completed the task.&nbsp; In the case of TaskCompletionSource&lt;TResult&gt;, that means that synchronous continuations can happen as part of a call to {Try}Set*, which means in our AsyncManualResetEvent example, those continuations could execute as part of the Set method.&nbsp; Depending on your needs (and whether callers of Set may be ok with a potentially longer-running Set call as all synchronous continuations execute), this may or may not be what you want.&nbsp; If you don&rsquo;t want this to happen, there are a few alternative approaches.&nbsp; One approach is to run the completion asynchronously, having the call to set block until the task being completed is actually finished (not including the task&rsquo;s synchronous continuations, just the task itself), e.g.<\/p>\n<blockquote>\n<p><span style=\"font-family: consolas;font-size: x-small\"><font size=\"2\"><span style=\"color: #0000ff\">public void<\/span> Set()           <br>{           <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">var<\/span> tcs = m_tcs;<\/font><\/span><span style=\"font-family: consolas;font-size: x-small\"><font size=\"2\">          <br>&nbsp;&nbsp;&nbsp; <span style=\"color: #4bacc6\">Task<\/span>.Factory.StartNew(s =&gt; ((<span style=\"color: #4bacc6\">TaskCompletionSource<\/span>&lt;<span style=\"color: #0000ff\">bool<\/span>&gt;)s).TrySetResult(<span style=\"color: #0000ff\">true<\/span>),           <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tcs, <span style=\"color: #4bacc6\">CancellationToken<\/span>.None, <span style=\"color: #4bacc6\">TaskCreationOptions<\/span>.PreferFairness, <span style=\"color: #4bacc6\">TaskScheduler<\/span>.Default);           <br>&nbsp;&nbsp;&nbsp; tcs.Task.Wait();           <br>}<\/font><\/span><\/p>\n<\/blockquote>\n<p>There are of course other possible approaches, and what you do depends on your needs.<\/p>\n<p>Next time, we&rsquo;ll take a look at implementing <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2012\/02\/11\/10266923.aspx\">an async auto-reset event<\/a>.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Task-based Async Pattern (TAP) isn&rsquo;t just about asynchronous operations that you initiate and then asynchronously wait for to complete.&nbsp; More generally, tasks can be used to represent all sorts of happenings, enabling you to await for any matter of condition to occur.&nbsp; We can even use Tasks to build simple coordination primitives like their [&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-423","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>The Task-based Async Pattern (TAP) isn&rsquo;t just about asynchronous operations that you initiate and then asynchronously wait for to complete.&nbsp; More generally, tasks can be used to represent all sorts of happenings, enabling you to await for any matter of condition to occur.&nbsp; We can even use Tasks to build simple coordination primitives like their [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/423","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=423"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/423\/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=423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}