title: How to wait for a single event in C#, with timeout and cancellation
body: <p>So my requirement is to have my function wait for the first instance an <code>event Action&lt;T&gt;</code> coming from another class and another thread, and handle it on my thread, allowing the wait to be interrupted by either timeout or <code>CancellationToken</code>.  </p>
  
  <p>I want to create a generic function I can reuse.  I managed to create a couple options that do (I think) what I need, but both seem more complicated than I'd imagine it should have to be.</p>
  
  <h1>Usage</h1>
  
  <p>Just to be clear, a sample use of this function would look like this, where <code>serialDevice</code> is spitting out events on a separate thread:</p>
  
  <pre><code>var eventOccurred = Helper.WaitForSingleEvent&lt;StatusPacket&gt;(
      cancellationToken,
      statusPacket =&gt; OnStatusPacketReceived(statusPacket),
      a =&gt; serialDevice.StatusPacketReceived += a,
      a =&gt; serialDevice.StatusPacketReceived -= a,
      5000,
      () =&gt; serialDevice.RequestStatusPacket());
  </code></pre>
  
  <h1>Option 1—ManualResetEventSlim</h1>
  
  <p>This option isn't bad, but the <code>Dispose</code> handling of the <code>ManualResetEventSlim</code> is messier than it seems like it should be.  It gives ReSharper fits that I'm accessing modified/disposed things within the closure, and it's genuinely hard to follow so I'm not even sure it's correct.  Maybe there's something I'm missing that can clean this up, which would be my preference, but I don't see it offhand.  Here's the code.</p>
  
  <pre><code>public static bool WaitForSingleEvent&lt;TEvent&gt;(this CancellationToken token, Action&lt;TEvent&gt; handler, Action&lt;Action&lt;TEvent&gt;&gt; subscribe, Action&lt;Action&lt;TEvent&gt;&gt; unsubscribe, int msTimeout, Action initializer = null)
  {
      var eventOccurred = false;
      var eventResult = default(TEvent);
      var o = new object();
      var slim = new ManualResetEventSlim();
      Action&lt;TEvent&gt; setResult = result =&gt; 
      {
          lock (o) // ensures we get the first event only
          {
              if (!eventOccurred)
              {
                  eventResult = result;
                  eventOccurred = true;
                  // ReSharper disable AccessToModifiedClosure
                  // ReSharper disable AccessToDisposedClosure
                  if (slim != null)
                  {
                      slim.Set();
                  }
                  // ReSharper restore AccessToDisposedClosure
                  // ReSharper restore AccessToModifiedClosure
              }
          }
      };
      subscribe(setResult);
      try
      {
          if (initializer != null)
          {
              initializer();
          }
          slim.Wait(msTimeout, token);
      }
      finally // ensures unsubscription in case of exception
      {
          unsubscribe(setResult);
          lock(o) // ensure we don't access slim
          {
              slim.Dispose();
              slim = null;
          }
      }
      lock (o) // ensures our variables don't get changed in middle of things
      {
          if (eventOccurred)
          {
              handler(eventResult);
          }
          return eventOccurred;
      }
  }
  </code></pre>
  
  <h1>Option 2—polling without a <code>WaitHandle</code></h1>
  
  <p>The <code>WaitForSingleEvent</code> function here is much cleaner.  I'm able to use <code>ConcurrentQueue</code> and thus don't even need a lock.  But I just don't like the polling function <code>Sleep</code>, and I don't see any way around it with this approach.  I'd like to pass in a <code>WaitHandle</code> instead of a <code>Func&lt;bool&gt;</code> to clean up <code>Sleep</code>, but the second I do that I've got the whole <code>Dispose</code> mess to clean up again.</p>
  
  <pre><code>public static bool WaitForSingleEvent&lt;TEvent&gt;(this CancellationToken token, Action&lt;TEvent&gt; handler, Action&lt;Action&lt;TEvent&gt;&gt; subscribe, Action&lt;Action&lt;TEvent&gt;&gt; unsubscribe, int msTimeout, Action initializer = null)
  {
      var q = new ConcurrentQueue&lt;TEvent&gt;();
      subscribe(q.Enqueue);
      try
      {
          if (initializer != null)
          {
              initializer();
          }
          token.Sleep(msTimeout, () =&gt; !q.IsEmpty);
      }
      finally // ensures unsubscription in case of exception
      {
          unsubscribe(q.Enqueue);
      }
      TEvent eventResult;
      var eventOccurred = q.TryDequeue(out eventResult);
      if (eventOccurred)
      {
          handler(eventResult);
      }
      return eventOccurred;
  }
  
  public static void Sleep(this CancellationToken token, int ms, Func&lt;bool&gt; exitCondition)
  {
      var start = DateTime.Now;
      while ((DateTime.Now - start).TotalMilliseconds &lt; ms &amp;&amp; !exitCondition())
      {
          token.ThrowIfCancellationRequested();
          Thread.Sleep(1);
      }
  }
  </code></pre>
  
  <h1>The question</h1>
  
  <p>I don't particularly care for either of these solutions, nor am I 100% sure either of them are 100% correct.  Is either one of these solutions better than the other (idiomaticity, efficiency, etc), or is there an easier way or built-in function to meet what I need to do here?</p>
  
  <h1>Update: Best answer so far</h1>
  
  <p>A modification of the <code>TaskCompletionSource</code> solution below.  No long closures, locks, or anything required.  Seems pretty straightforward.  Any errors here?</p>
  
  <pre><code>public static bool WaitForSingleEvent&lt;TEvent&gt;(this CancellationToken token, Action&lt;TEvent&gt; onEvent, Action&lt;Action&lt;TEvent&gt;&gt; subscribe, Action&lt;Action&lt;TEvent&gt;&gt; unsubscribe, int msTimeout, Action initializer = null)
  {
      var tcs = new TaskCompletionSource&lt;TEvent&gt;();
      Action&lt;TEvent&gt; handler = result =&gt; tcs.TrySetResult(result);
      var task = tcs.Task;
      subscribe(handler);
      try
      {
          if (initializer != null)
          {
              initializer();
          }
          task.Wait(msTimeout, token);
      }
      finally
      {
          unsubscribe(handler);
          // Do not dispose task http://blogs.msdn.com/b/pfxteam/archive/2012/03/25/10287435.aspx
      }
      if (task.Status == TaskStatus.RanToCompletion)
      {
          onEvent(task.Result);
          return true;
      }
      return false;
  }
  </code></pre>
  
  <h1>Update 2: Another great solution</h1>
  
  <p>Turns out that <code>BlockingCollection</code> works just like <code>ConcurrentQueue</code> but also has methods accepting a timeout and cancellation token.  One nice thing about this solution is that it can be updated to make a <code>WaitForNEvents</code> fairly easily:</p>
  
  <pre><code>public static bool WaitForSingleEvent&lt;TEvent&gt;(this CancellationToken token, Action&lt;TEvent&gt; handler, Action&lt;Action&lt;TEvent&gt;&gt; subscribe, Action&lt;Action&lt;TEvent&gt;&gt; unsubscribe, int msTimeout, Action initializer = null)
  {
      var q = new BlockingCollection&lt;TEvent&gt;();
      Action&lt;TEvent&gt; add = item =&gt; q.TryAdd(item);
      subscribe(add);
      try
      {
          if (initializer != null)
          {
              initializer();
          }
          TEvent eventResult;
          if (q.TryTake(out eventResult, msTimeout, token))
          {
              handler(eventResult);
              return true;
          }   
          return false;
      }
      finally
      {
          unsubscribe(add);
          q.Dispose();
      }
  }
  </code></pre>