C #~ Asynchronous programming continues ~ W3wp.exe crash triggered by awaitand async- problem-friendly solution,
Reasons for deadlocks
The reason for understanding the damn lock is to understand how await processes contexts. By default, when an unfinished Task is await, the current context will re-obtain and continue executing the remaining code when the Task is completed. This context is the current SynchronizationContext, unless it is empty. SynchronizationContext of WEB applications is exclusive and only one thread is allowed to run. When await is finished, it tries to execute its remaining part in its original code context, but there is already a thread in the context of the Code, that is the thread that has been waiting for async to complete synchronization. The two of them are waiting for each other, so they are deadlocked.
Pay attention to the asynchronous usage of MSDN.
Rules |
Description |
Exceptions |
Avoid using async void |
Prioritize the use of async tasks instead of async void |
Event handlers |
Async to top |
Do not mix blocking and async code |
Console main method |
Note that the context for execution is configured. |
Set ConfigureAwait (false) whenever possible) |
Except for those requiring context |
Grateful heart
Thanks for sharing many articles on the Internet. In related articles, I found a non-blocking solution for using asynchronous code in synchronous code. I also wrote several test demos myself, however, the Asynchronous Method with return values such as Task <T> still has a deadlock. The previous Code is as follows:
/// <Summary> // uncle test /// </summary> public class tools {# region assume that these methods are encapsulated by a third party, the public static async Task TestAsync () {await Task. delay( 1000 ). configureAwait (false); // No Deadlock} public static async Task <string> GetStrAsync () {return await Task. run () => "OK "). configureAwait (false);} public static async Task DelayTestAsync () {Logger. loggerFactory. instance. logger_Info ("DelayAsync"); await Task. delay( 1000);} public static async Task <string> DelayGetStrAsync () {return await Task. run () => "OK") ;}# endregion # region we need to encapsulate it in our own code, solve the thread deadlock // <summary> // synchronously call an asynchronous entity without return values // </summary> // <param name = "func"> </ param> public static void ForWait (Func <Task> func) {func (). configureAwait (false );} /// <summary> /// an asynchronous object that has returned values synchronously called // </summary> /// <typeparam name = "T"> </typeparam>/ // <param name = "func"> </param> // <returns> </returns> public static T ForResult <T> (Func <Task <T> func) {var a = func ();. configureAwait (false); return. result ;}# endregion}
For the above Code, when executing a Task reverse return type (that is, there is no returned result), the program is no problem, but there can be returned results, the above ForResult method will still generate deadlocks! I certainly won't stop here. After finding some articles, I finally got the result and simplified the current context and asynchronous context.
After processing a ticket,Finally, synchronization and Asynchronization are achieved.,Therefore, people are the smartest animal. Everything is possible, as long as you think!
The Code of Lind. DDD. Utils. AsyncTaskManager is as follows, hoping to provide some inspiration and help.
/// <Summary> // asynchronous thread management-call asynchronous in a synchronization program, solved the thread deadlock issue. // </summary> public class AsyncTaskManager {// <summary> // run the Asynchronous Method without return type. /// </summary>/ // <param name = "task"> </param> public static void RunSync (Func <Task> task) {var oldContext = SynchronizationContext. current; // synchronous context var synch = new ExclusiveSynchronizationContext (); // asynchronous context SynchronizationContext. setSynchronizationContext (synch); // sets the current synchronization context sy Nch. post (async obj =>{ try {await task ();} catch (Exception e) {synch. innerException = e; throw;} finally {synch. endMessageLoop () ;}}, null); synch. beginMessageLoop (); SynchronizationContext. setSynchronizationContext (oldContext );} /// <summary> /// run the asynchronous method whose return type is T /// </summary> /// <typeparam name = "T"> </typeparam>/ // <param name = "task"> </param> // <returns> </returns> public static T RunSy Nc <T> (Func <Task <T> task) {var oldContext = SynchronizationContext. current; var synch = new ExclusiveSynchronizationContext (); SynchronizationContext. setSynchronizationContext (synch); T ret = default (T); // The default value of the action is synch. post (async obj =>{ try {ret = await task ();} catch (Exception e) {synch. innerException = e; throw;} finally {synch. endMessageLoop () ;}}, null); synch. beginMessageLoop (); Sync HronizationContext. setSynchronizationContext (oldContext); return ret ;}/// <summary> // asynchronous context object /// </summary> class ExclusiveSynchronizationContext: SynchronizationContext {private bool done; public Exception InnerException {get; set;} readonly AutoResetEvent workItemsWaiting = new AutoResetEvent (false); readonly Queue <Tuple <SendOrPostCallback, object> items = new Queue <Tuple <SendOrPostCal Lback, object >>(); public override void Send (SendOrPostCallback d, object state) {throw new NotSupportedException ("We cannot send to our same thread ");} /// <summary> /// add to asynchronous queue /// </summary> /// <param name = "d"> </param> /// <param name = "state"> </param> public override void Post (SendOrPostCallback d, object state) {lock (items) {items. enqueue (Tuple. create (d, state);} workItemsWaiting. set () ;} // <Summary> /// asynchronous end // </summary> public void EndMessageLoop () {Post (obj => done = true, null );} /// <summary> /// process messages in the asynchronous queue /// </summary> public void BeginMessageLoop () {while (! Done) {Tuple <SendOrPostCallback, object> task = null; lock (items) {if (items. count> 0) {task = items. dequeue () ;}} if (task! = Null) {task. Item1 (task. Item2); if (InnerException! = Null) // the method threw an exeption {throw new aggresponexception ("AsyncInline. run method threw an exception. ", InnerException) ;}} else {workItemsWaiting. waitOne () ;}} public override SynchronizationContext CreateCopy () {return this ;}}}
Finally, we are testing and we can see that there is no deadlock in the thread!
Uncle await & async article list
C #~ Asynchronous programming continues ~ W3wp.exe crash caused by awaitand async
C #~ Asynchronous programming continues ~ Parallel async asynchronous and synchronous Methods
The foundation is the top priority ~ The cost of multithreading ~ My memory has been eaten!
EF architecture ~ The path to EF asynchronous Transformation ~ Warehouse interface transformation ~ Continued
EF architecture ~ The path to EF asynchronous Transformation ~ Enable DbContextRepository to Implement Asynchronous Interfaces
EF architecture ~ The path to EF asynchronous Transformation ~ Warehouse interface Transformation
C #~ Asynchronous programming continued ~. Net4.5 main await & async applications
C #~ Asynchronous programming
Thank you for reading this article!