wait for the UI thread to complete or cancel the wait using System;
using System.Diagnostics;
using System.Threading;

class Program
{
  public static void Main()
  {
     ThreadPool.QueueUserWorkItem(() =&gt; {
        Thread.Sleep(10000);
        PressAnyKey.Cancel();
     });
     Console.WriteLine("Press Any Key or don't...");
     PressAnyKey.WaitOne();
  }
}

internal class PressAnyKey
{
  private static Thread inputThread;
  private static AutoResetEvent getInput;
  private static AutoResetEvent gotInput;
  private static CancellationTokenSource cancellationtoken;

  static PressAnyKey()
  {
    // Static Constructor called when WaitOne is called (technically Cancel too, but who cares)
    getInput = new AutoResetEvent(false);
    gotInput = new AutoResetEvent(false);
    inputThread = new Thread(ReaderThread);
    inputThread.IsBackground = true;
    inputThread.Name = "PressAnyKey";
    inputThread.Start();
  }

  private static void ReaderThread()
  {
    while (true)
    {
      // ReaderThread waits until PressAnyKey is called
      getInput.WaitOne();
      // Get here 
      // Inner loop used when a caller uses PressAnyKey
      while (!Console.KeyAvailable &amp;&amp; !cancellationtoken.IsCancellationRequested)
      {
        Thread.Sleep(50);
      }
      // Release the thread that called PressAnyKey
      gotInput.Set();
    }
  }

  /// &lt;summary&gt;
  /// Signals the thread that called WaitOne should be allowed to continue
  /// &lt;/summary&gt;
  public static void Cancel()
  {
    // Trigger the alternate ending condition to the inner loop in ReaderThread
    if(cancellationtoken== null) throw new InvalidOperationException("Must call WaitOne before Cancelling");
    cancellationtoken.Cancel();
  }

  /// &lt;summary&gt;
  /// Wait until a key is pressed or &lt;see cref="Cancel"/&gt; is called by another thread
  /// &lt;/summary&gt;
  public static void WaitOne()
  {
    if(cancellationtoken==null || cancellationtoken.IsCancellationRequested) throw new InvalidOperationException("Must cancel a pending wait");
    cancellationtoken = new CancellationTokenSource();
    // Release the reader thread
    getInput.Set();
    // Calling thread will wait here indefiniately 
    // until a key is pressed, or Cancel is called
    gotInput.WaitOne();
  }    
}
Is there any reason you don't just use the cancellation token to stop the thread? I'm also wondering why you're using an explicit thread at all. This is asynchronous programming the hard way. async-await and Tasks are the idiomatic way to do this for the last several versions of the language &amp; framework. 

I'm imagining your code looking something like this. (Totally untested. Might not compile.)

public static void Main()
{
    var cts = new CancellationTokenSource();
    var token = cts.Token;

    Task.Run(()=&gt;
    {
        while (!Console.KeyAvailable)
        {
            if (token.IsCancellationRequested)
            {
                token.ThrowIfCancellationRequested();
            }

            await Task.Delay(50);
        }

        token.Cancel();
     }, token);

     Console.WriteLine("Press Any Key or don't...");

     await Task.Delay(50000, token);
     token.Cancel(); //task is still running, best to shut it down too
 }