Reputation: 1048
I'm working on a small WPF desktop utility and am using the async/await methodology to allow things to process in parallel.
However, I keep running into issues where an awaited async Task simply never returns. No exceptions are thrown, and if I pause the app in the debugger, the call stack says it is running "External code" called by the line where the async task is called. (Specifically, it hangs at: WindowsBase.dll!System.Windows.Threading.DispatcherSynchronizationContext.Wait(System.IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) on my current example of this.) I've seen this several times and worked around it, but each time I have to add debugging code to figure out what line things stopped executing on. (The same code might execute fine for several iterations, and then hang) The same issue has happened both on awaiting my own async methods and on awaiting framework async methods E.G. Stream.CopyToAsync and Stream.ReadAsync)
Is there a way to look into executing Tasks in Visual Studio 2017? I tried opening the "Tasks" window, but I've never gotten anything but "No tasks to display" -- possibly I'm not using that window correctly?
FWIW, I'm doing a lot (hundreds) of concurrent background operations, but none overlap. Mostly web service calls, file system reads and MD5 checksum computations. Is the async/await limited in what it can do concurrently without freezing up? Or a maximum nesting of awaits?
Upvotes: 0
Views: 3966
Reputation: 39007
This looks like a classic case of deadlock due to the synchronization context. This happens when you wait synchronously on a task returned by a method that internally calls await
. For instance:
public void Deadlock()
{
DoSomething.Wait();
}
public Task DoSomething()
{
// Some stuff
await DoSomethingElse();
// More stuff
}
When inside of a synchronization context, the continuation of await
is posted to that very same synchronization context. But the thread of the synchronization context is waiting on the DoSomething().Wait()
, and therefore not available. We have a deadlock:
There are two possible fix:
.ConfigureAwait(false)
when awaiting, so that the continuation isn't posted to the synchronization contextUpvotes: 8