4

I've read here https://blog.stephencleary.com/2009/10/synchronizationcontext-properties.html that ASP.NET applications' execution context does not have specific associated thread. Does it mean code after await will(can) be executed in different thread with the same context ? In this case how it is possible that deadlock can be caused by synchronous execution? Or ASP.NET application is not the case for such deadlock ?

Thanks in advance.

Denys Alexieiev
  • 224
  • 1
  • 15
  • 1
    ASP.NET supplies a different thread per HTTP request, and the specific thread might actually change due to [thread agility](https://stackoverflow.com/questions/11306888/what-is-the-meaning-of-thread-agility-in-asp-net). That being said, a particular HTTP request will only be handled by one thread *at a time*, which is why you don't have to `lock` around most variables. The exception is if you go out of your way to make it work otherwise, e.g. by using `Task.Run`. – John Wu Feb 03 '20 at 22:53
  • I think what is meant in that article is that ASP.Net classic has a synchronization context, i.e. deadlocking will happen when continuation tries to run on blocking call but there is no specific associated thread like there is with Winforms where there is a main/GUI thread attached to synchronization – JohanP Feb 03 '20 at 23:06
  • @JohnWu, does it mean if some thread is already executing in http request and was blocked because of deadlock, then no other thread can continue execution ? – Denys Alexieiev Feb 03 '20 at 23:12
  • Not exactly... Other threads can run some other code not related to *the original request* (maybe handling some other request), that deadlock (between blocked thread tied to the synchronization context of original request and the async operation trying to continue on that context) will only impact *one* thread, the async operation waiting for continuation to run will not consume additional thread for itself. – Alexei Levenkov Feb 04 '20 at 00:14

1 Answers1

4

For ASP.NET Classic (.NET Framework), there is a special AspNetSynchronizationContext, the continuation will post back to the original context thread.

ASP.NET Core there isn’t one. If you inspect SynchronizationContext.Current you’ll find that it’s set to null. As such, a continuation is free to use what ever thread it chooses, and will suffer no classic deadlocks in that respect


Update

Some great corrections from @StephenCleary in the comments

Minor correction : on classic ASP.NET, the SynchronizationContext represents the request context, not a specific thread.

The method may resume on any thread pool thread after the await. The deadlock occurs because there is a lock as part of that request context to ensure that only one thread at a time may be in the request context.

So, when the async method is ready to resume, a thread pool thread is taken which enters the request context and tries to take that lock. If there's another thread blocked on that task in the context, the lock is already taken and a deadlock will occur

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • 1
    You say for .NET Framework case the continuation will post back to the original context, however, as I know context != original thread. John Wu above mentioned thread agility. Is it case for .NET Framework? Can the Thread Pool just create new thread and assign AspNetSynchronizationContext to it and continue execution if the original thread is busy ? – Denys Alexieiev Feb 03 '20 at 23:02
  • @DenysAlexieiev If you are in a framework which has a *SynchronizationContext* don't block on `async` its as simple as that really, you run the likely risk of a deadlock. What problem are you trying to solve? – TheGeneral Feb 03 '20 at 23:05
  • Not sure I understand your last answer. Could you please add more details ? – Denys Alexieiev Feb 03 '20 at 23:08
  • I am not really solving some problem. Just trying to understand how this stuff works. – Denys Alexieiev Feb 03 '20 at 23:09
  • 4
    @DenysAlexieiev the Q&A format is not really the right place for an in depth deep dive question and answer trail, maybe if you take a look at this first https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html , if you have more questions after that potentially you can post again. – TheGeneral Feb 03 '20 at 23:13
  • Thanks. Good article – Denys Alexieiev Feb 03 '20 at 23:31
  • 4
    Minor correction: on classic ASP.NET, the `SynchronizationContext` represents the request context, *not* a specific thread. The method may resume on any thread pool thread after the `await`. The deadlock occurs because there is a lock as part of that request context to ensure that only one thread at a time may be in the request context. So, when the `async` method is ready to resume, a thread pool thread is taken which enters the request context and tries to take that lock. If there's another thread blocked on that task in the context, the lock is already taken and a deadlock will occur. – Stephen Cleary Feb 04 '20 at 02:20
  • @StephenCleary thanks for those corrections, i wasnt happy with the way i worded that. I have updated it with your comments and attributed them, and also learnt some more in the process. cheers! – TheGeneral Feb 04 '20 at 02:29