2

For logging purposes of an ASP.NET web application, I keep some state information in a static class. These fields are marked [ThreadStatic] so every thread has its own copy of the field. The logging methods are called from the HttpApplication event methods:

  • Application_BeginRequest (request start, initialise state)
  • Application_AcquireRequestState (session and user are known)
  • Application_EndRequest (request end, clean up)

I can now observe that, under certain circumstances, a page request is processed in different threads. The BeginRequest event runs on thread 18 while the following events run on thread 4. Of course my thread-static data is then not available and an error occurs.

Most of the time this works just fine and every request is processed in a single thread only. But when I request a page that loads ~5 seconds and after 1-2 seconds click on another link, both requests run in parallel. The first is completed on thread 24 (where it was also started) after 5 seconds, while the other starts on thread 18, but after the first request has completed, the second continues to run on thread 4.

Trying it with 3 overlapping long requests, it's a pure chaos. I can even watch two requests starting on the same thread while they later continue on different threads each. There doesn't seem to be any relationship between a request and a thread.

How can it be that a request is changing threads? It's losing all of its state if it decides to move on to another thread. And every description I can find says that it all happens in a single thread.

ASP.NET 4.0 on IIS 7, Windows Server 2008 R2, x64.

Alternative: If I cannot rely on requests being processed in only a single thread from the start to the end, then what would be the best location to store small amounts of per-request data (currently an integer and a class) that is very fast accessibly? And preferably also works without a reference to System.Web (my code is targeting the client profile as well). I know about HttpContext.Current.Items[key] but it's looked up somewhere deep in the remoting assembly and involves a dictionary which seems a lot slower than a thread-static field.

ygoe
  • 18,655
  • 23
  • 113
  • 210
  • 1
    Where have you seen any guarantees that only a single thread is used? – John Saunders Jun 06 '14 at 14:04
  • I can't find any references right now, but everywhere I read about how this works, they say that each request runs on one of the existing HttpApplication instances which all run in their own thread. – ygoe Jun 06 '14 at 14:06
  • Here's a reference: "There are actually multiple instances of HttpApplication active at any given time depending on the load on the application and each instance processes requests on its own separate thread." (http://weblog.west-wind.com/posts/2009/Jun/18/How-do-ASPNET-Application-Events-Work) – ygoe Jun 06 '14 at 14:25
  • 1
    Did you notice the date of the reference? That may have been true five years ago. Also, that says "their own separate thread", not "their own _dedicated_ thread". – John Saunders Jun 06 '14 at 14:26
  • 1
    `HttpContext.Current.Items[key]` is the *Supported* way to do what you want. Unless you have tested `seems a lot slower than a thread-static field` or actually have a problem, it would appear you are going down the rabbit hole of pre-optimization. – Erik Philips Jun 06 '14 at 14:27

1 Answers1

4

ASP.NET is thread agile and a request can be processed on more than one thread (but not more than one at time). Because of this you really can't use ThreadStatics in ASP.NET. However, you can safely use the HttpContext.Items dictionary to store things which need to be scoped to a single request.

To allow your code to work outside the context of an ASP.NET application, you could create a wrapper that swaps HttpContext / CallContext, depending on which environment the code is in. Here is an example of such a wrapper.

Community
  • 1
  • 1
Jay Douglass
  • 4,828
  • 2
  • 27
  • 19
  • Not only that, threads can be re-used by new requests. (Thread pooling). This is an even more important reason never to use ThreadStatic in ASP.NET – MarkO Jun 06 '14 at 14:30