title: Simulate async deadlock in a console application
body: <p>Usually, an async deadlock occurs in UI thread or with ASP.NET context. I'm trying to simulate the deadlock in a console application so that I can unit test my library codes.</p>
  
  <p>So here's my attempt:</p>
  
  <pre><code>class Program
  {
      private static async Task DelayAsync()
      {
          Console.WriteLine( "DelayAsync.Start" );
          await Task.Delay( 1000 );
          Console.WriteLine( "DelayAsync.End" );
      }
  
      // This method causes a deadlock when called in a GUI or ASP.NET context.
      public static void Deadlock()
      {
          Console.WriteLine( "Deadlock.Start" );
          // Start the delay.
          var delayTask = DelayAsync();
          // Wait for the delay to complete.
          delayTask.Wait();
          Console.WriteLine( "Deadlock.End" );
      }
  
      static void Main( string[] args )
      {
          var thread = new Thread( () =&gt; 
          {
              Console.WriteLine( "Thread.Start" );
              SynchronizationContext.SetSynchronizationContext( new DedicatedThreadSynchronisationContext() );
              Deadlock();
              Console.WriteLine( "Thread.End" );
          } );
          thread.Start();
          Console.WriteLine( "Thread.Join.Start" );
          thread.Join();
          Console.WriteLine( "Thread.Join.End" );
          Console.WriteLine( "Press any key to exit" );
          Console.ReadKey( true );
          Console.WriteLine( "Pressed" );
      }
  }
  </code></pre>
  
  <p>So <strong>Deadlock()</strong> should cause a deadlock in an right context.
  To simulate the ASP.NET context, I'm using <strong>DedicatedThreadSynchronisationContext</strong> from <a href="https://stackoverflow.com/a/31714115/121240">https://stackoverflow.com/a/31714115/121240</a>:</p>
  
  <pre><code>public sealed class DedicatedThreadSynchronisationContext : SynchronizationContext, IDisposable
  {
      public DedicatedThreadSynchronisationContext()
      {
          m_thread = new Thread( ThreadWorkerDelegate );
          m_thread.Start( this );
      }
  
      public void Dispose()
      {
          m_queue.CompleteAdding();
      }
  
      /// &lt;summary&gt;Dispatches an asynchronous message to the synchronization context.&lt;/summary&gt;
      /// &lt;param name="d"&gt;The System.Threading.SendOrPostCallback delegate to call.&lt;/param&gt;
      /// &lt;param name="state"&gt;The object passed to the delegate.&lt;/param&gt;
      public override void Post( SendOrPostCallback d, object state )
      {
          if ( d == null ) throw new ArgumentNullException( "d" );
          m_queue.Add( new KeyValuePair&lt;SendOrPostCallback, object&gt;( d, state ) );
      }
  
      /// &lt;summary&gt; As 
      public override void Send( SendOrPostCallback d, object state )
      {
          using ( var handledEvent = new ManualResetEvent( false ) )
          {
              Post( SendOrPostCallback_BlockingWrapper, Tuple.Create( d, state, handledEvent ) );
              handledEvent.WaitOne();
          }
      }
  
      public int WorkerThreadId { get { return m_thread.ManagedThreadId; } }
      //=========================================================================================
  
      private static void SendOrPostCallback_BlockingWrapper( object state )
      {
          var innerCallback = ( state as Tuple&lt;SendOrPostCallback, object, ManualResetEvent&gt; );
          try
          {
              innerCallback.Item1( innerCallback.Item2 );
          }
          finally
          {
              innerCallback.Item3.Set();
          }
      }
  
      /// &lt;summary&gt;The queue of work items.&lt;/summary&gt;
      private readonly BlockingCollection&lt;KeyValuePair&lt;SendOrPostCallback, object&gt;&gt; m_queue =
          new BlockingCollection&lt;KeyValuePair&lt;SendOrPostCallback, object&gt;&gt;();
  
      private readonly Thread m_thread = null;
  
      /// &lt;summary&gt;Runs an loop to process all queued work items.&lt;/summary&gt;
      private void ThreadWorkerDelegate( object obj )
      {
          SynchronizationContext.SetSynchronizationContext( obj as SynchronizationContext );
  
          try
          {
              foreach ( var workItem in m_queue.GetConsumingEnumerable() )
                  workItem.Key( workItem.Value );
          }
          catch ( ObjectDisposedException ) { }
      }
  }
  </code></pre>
  
  <p>I set the context before calling Deadlock():</p>
  
  <pre><code>SynchronizationContext.SetSynchronizationContext( new DedicatedThreadSynchronisationContext() );
  </code></pre>
  
  <p>I expect the code to hang on this line because it should capture the context:</p>
  
  <pre><code>await Task.Delay( 1000 );
  </code></pre>
  
  <p>However , it passes just fine and the program runs through the end, and it prints "Pressed". (Although the program hangs on DedicatedThreadSynchronisationContext.ThreadWorkerDelegate() so it doesn't exist, but I consider it a minor issue.)</p>
  
  <p>Why doesn't it produce a dead lock? What is the proper way to simulate a  dead lock?</p>
  
  <p>========================================</p>
  
  <h1>EDIT</h1>
  
  <p>As per the answer by Luaan, </p>
  
  <p>I used DedicatedThreadSynchronisationContext.Send() instead of creating a new thread:</p>
  
  <pre><code>        Console.WriteLine( "Send.Start" );
          var staContext = new DedicatedThreadSynchronisationContext();
          staContext.Send( ( state ) =&gt;
          {
              Deadlock();
          }, null );
          Console.WriteLine( "Send.End" );
  </code></pre>
  
  <p>It lets Deadlock() to run under the context, so 'await' captures the same context thus a dead lock occurs.</p>
  
  <p>Thank you Luaan!</p>