Search code examples
c#asynchronousdeadlock

Specific deadlock scenario when using asynchronous code


I've read for hours about the Task based Asynchronous Pattern. And now I try to prove myself I understood it properly, so I forced myself into the following excercice:

Inside a WebApi controller, wait for an async operation in a non async one and try to access ControllerContext afterward. But things don't flow the way I though they would.

EDIT: Code misleading, don't consider it...

//using System.Diagnostics;
//using System.Threading.Tasks;
//using System.Web.Http;
//namespace DeadlockTest.Controllers
//{
//    public class ValuesController : ApiController
//    {
//        public string Get()
//        {
//            var task = DoSomething();
//            //task.Wait();
//            task.ConfigureAwait(false).GetAwaiter().GetResult();
//            return ControllerContext?.ToString();  // not reached
//        }
//        private async Task DoSomething()
//        {
//            await Task.Delay(new System.TimeSpan(0, 0, 0, 0, 100));
//            Debugger.Break(); // not reached
//        }
//    }
//}

I'm astonished Debugger.Break(); is not reached!

Even if I just call task.Wait();.

task.ConfigureAwait(false).GetAwaiter().GetResult(); is a bit awkward and it's just a random shot at being able to wait for a task which shouldn't "block" the current SynchronizationContext.

How can this be solved, knowing the methods signature must not change* (for this exercice to bear any meaning to me)?

  • thus no public async string Get() to save the day

EDIT:

    public void LogGet()
    {
        Action get = Get;
        var logger = new RussianOpCodeLibrary.ActionLogger(get);

        logger.Dosvidaniya();
    }

    private void Get()
    {
        DoSomething().Wait();
    }

    private async Task DoSomething()
    {
        await Task.Delay(new System.TimeSpan(0, 0, 0, 0, 100));

        Debugger.Break(); // not reached
    }

Solution

  • I guess I can solve this using Delegate Tasks.

        public string Get()
        {
            Task.Factory.StartNew(() =>
            {
                var task = DoSomething();
                task.Wait();
            }).Wait();
    
            Task.Factory.StartNew(async () =>
            {
                var task = DoSomething();
                await task;
            }).Unwrap().Wait();
            //task.ConfigureAwait(false).GetAwaiter().GetResult();
    
            return ControllerContext?.ToString();
        }