title: How to cancel Stream.ReadAsync?
body: <p>Why doesn't the code below ever complete if you don't type any input, and why does it still respond to a key being pressed even after the cancellation token has been canceled?</p>
  
  <pre><code>// Set up a cancellation token
  var cancellationSource = new CancellationTokenSource();
  
  // Cancel the cancellation token after a little bit of time
  Task.Run(async () =&gt;
  {
      await Task.Delay(TimeSpan.FromSeconds(2));
      cancellationSource.Cancel();
      Console.WriteLine("Canceled the cancellation token");
  });
  
  // Wait for user input, or the cancellation token
  Task.Run(async () =&gt;
  {
      try
      {
          using (var input = Console.OpenStandardInput())
          {
              var buffer = new byte[1];
              Console.WriteLine("Waiting for input");
              await input.ReadAsync(buffer, 0, 1, cancellationSource.Token); // This is impossible to cancel???
              Console.WriteLine("Done waiting for input"); // This never happens until you press a key, regardless of the cancellation token
          }
      }
      catch (Exception e)
      {
          Console.WriteLine(e.Message); // No errors
      }
  })
  .Wait(); // Block until complete
  </code></pre>
  
  <p><a href="https://msdn.microsoft.com/en-us/library/hh193669(v=vs.110).aspx" rel="noreferrer" title="the documentation">The documentation for Stream.ReadAsync says</a>:</p>
  
  <blockquote>
    <p>If the operation is canceled before it completes, the returned task contains the Canceled value for the Status property.</p>
  </blockquote>
  
  <p>This implies that canceling the cancellation token will cancel the operation, right? Yet for some reason <a href="https://referencesource.microsoft.com/#mscorlib/system/io/stream.cs,e224b4bec8748849" rel="noreferrer">the source code for Stream.ReadAsync</a> doesn't do anything with the cancellation token if it isn't canceled beforehand:</p>
  
  <pre><code>public virtual Task&lt;int&gt; ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  {
      // If cancellation was requested, bail early with an already completed task.
      // Otherwise, return a task that represents the Begin/End methods.
      return cancellationToken.IsCancellationRequested
                  ? Task.FromCancellation&lt;int&gt;(cancellationToken)
                  : BeginEndReadAsync(buffer, offset, count);
  }
  </code></pre>
  
  <p>Therefore the cancellation token parameter is pointless--how can I cancel that async read?</p>