I noticed this morning that Scott Hanselman gave his blog a facelift. I also noticed that I had missed a flurry of post by him. On an ordinary day, by my reckoning, Scott is a heavy blogger. Apparently travel ups the volume that much more. FWIW, I tend to agree with most everything he has to say, and I have much respect for him.
Now.
He discusses storing things on threads and references previous post on the evils of ThreadStaticAttribute in the [Http]Context of ASP.NET. I think a bit of clarification is in order.
- ThreadStaticAttribute is not harmful in ASP.NET *if* you use it in a way that takes into account the context (sic) in which you are using it.
- Thread Local Storage suffers from problems similar to ThreadStaticAttribute in contexts where you do not control the lifecycle of the threads in the application, e.g. anywhere that uses the default ThreadPool, e.g. ASP.NET.
On point 1. If you initialize a ThreadStatic variable at the beginning of a request, and you properly dispose of the referenced object at the end of the request, I am going to go out on a limb and claim that nothing bad will happen. You're even cool between contexts in the same AppDomain.
Now, if you expect that variable to follow you outside the process, e.g. in a web service call, of course, you are wrong. If you expect the variable to magically jump from the currently executing thread onto a new thread that you spawn (via either of new Thread(...) or BeginInvoke and friends), then you are smoking something.
You may have problems if the assembly in which the ThreadStatic variable is not domain neutral, i.e. reloaded for each AppDomain in the process. In fact, you may have problems in spite of that. I haven't written any tests to verify either way, though.
All that being said, in the nominal use of ASP.NET (each request gets exclusive access to a thread for its lifetime and doesn't spawn any additional threads that require access to value referenced by the variable), then I think you'll be ok.
Now, I could be wrong on this. The clr could potentially stop a managed thread mid-stream, serialize out its stack somewhere, give it a new stack, and let it start executing. I seriously doubt it. I suppose that it is conceivable that hyperthreading makes things difficult as well, but I also doubt that.
On point 2: If you use slots in thread local storage on a ThreadPool thread and you don't clear out the data associated with the slot, it is going to be there when you get back in the context of another request, so expect that.
It is very likely that the objects that you are going to want to hold on to in some context-affine manner, be it a roll-your-own context affinity such as thread local or threadstatic, or a framework provided version such as Context, are expensive things like transactions, and further they either are or are holding onto scarce resources. For scalability reasons, regardless of how you approach the problem, you will want to make sure to let go of these objects, potentially disposing of them as early as possible to release the resources.
So -- the challenge (heh): Scott, if you can prove me wrong I will buy you a steak [assuming you like steak] dinner when you are here in Dallas for the .NET UG meeting in November (unless our paths serendipitously overlap before then).
I'll try to throw some sample code up to support these points at a later point. I would love to be wrong, because then I would probably learn something very tricky and interesting about what .NET keeps under its kilt. I just don't think I am.
Recent Comments