libplctag/libplctag.NET

Deadlock if Async Read/Write called from UI Thread

bwcurless opened this issue · 2 comments

I've recently ran into an issue where we want to use the async read/write functions for increased speed but can't migrate the entire codebase to async/await all the way to the top. I think this situation probably applies to others as well. In this case if you call the async tag read or write functions from a UI context (In my case a button clicked event handler), and if you call Task.GetAwaiter().GetResult() to block and wait for the read/write to complete then the UI thread deadlocks. The UI thread is blocked at this point, but all the continuations (the code executed after the await's in the library) were set up to run on the UI thread once the TaskCompletionSource completes.

In order to fix this deadlock it's pretty simple. You just need to set ConfigureAwait(false) on every single instance of a Task being awaited in the library (and even the consumer code that might await the async Read/Write methods). From my own research this seems to be the best thing to do for library code. There are different recommendations for non-library code but I'll leave some of the many references I've found on this matter.

https://www.gabescode.com/dotnet/2022/02/04/dont-use-configureawait.html <--See "Library" section

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

I've put my fix in this PR.
#351

Thanks for raising this - I've release this change as libplctag v1.2.0-alpha.1

Thank you very much. That was so fast too! I'll pull the new package in to my project today.