This project has moved and is read-only. For the latest updates, please go here.

Deadlocks

Aug 14, 2014 at 10:20 PM
Hi,

Thanks for this great library! I think this should have been part of the framework.

I was wondering about something - isn't it harder to detect deadlocks that occur using Nito.AsyncEx? In synchronous thread programming we can see that a Thread is waiting for a lock and by examining stacktrace we can understand how a deadlock occurred.

How do you suggest to detect deadlocks that occur using this library? For example in this code?
class Program
{
    private static AsyncMonitor Monitor1 = new AsyncMonitor();
    private static AsyncMonitor Monitor2 = new AsyncMonitor();

    static void Main(string[] args)
        {
            var task1 = Method1();
            var task2 = Method2();

            Console.ReadLine();

            Console.ReadLine();
        }

    private async static Task Method1()
        {
            using (await Monitor1.EnterAsync())
            {
                await Task.Delay(1000);

                using (await Monitor2.EnterAsync())
                {

                }
            }
        }

    private async static Task Method2()
        {
            using (await Monitor2.EnterAsync())
            {
                await Task.Delay(1000);

                using (await Monitor1.EnterAsync())
                {

                }
            }
        }
}
Thanks for your response
Aug 15, 2014 at 1:07 AM
Yes, it is harder to detect async deadlocks; this is true for await in general.

This is something I hope will be addressed by Visual Studio tooling in the future. I did play around with building something (actually based on ETW events raised by AsyncEx), but it was never completed. Maybe someday...

-Steve
Aug 15, 2014 at 10:50 AM
Ok, thanks for your reply.

I noticed we have in Visual Studio 2013 the Tasks window that shows the tasks that are be awaited, but it can only show the await line, and not the entire call stack and local variables.

Hope the Visual Studio team will improve this.
Aug 15, 2014 at 1:42 PM
I am hoping that the tooling will improve over time.

"Call stack" might be a while, though, because it doesn't actually mean what people think it means. The call stack is technically what the code will do next, not where it came from. These two things are the same for synchronous code but different for asynchronous code. Asynchronous code has a lot more complexity when you consider things like Task.WhenAny, too.

If you want a more heavyweight solution, you can check out my AsyncDiagnostics library: https://github.com/StephenCleary/AsyncDiagnostics
By default it just keeps track of the causality stack (where the code came from); you'd have to add local variable values yourself, and then actually call AsyncDiagnosticStack.Current from the debugger to see what the causality stack is at that time. It's definitely not perfect for your needs, but you can always just use it temporarily if you need to track down a particular issue.

-Steve