Storing things on Threads
There's so many places to put stuff. I think one of the most difficult things for new .NET developers is deciding where to store objects and bits of data.
There's certainly the obvious starting points:
- Local variables: Variables exist for a short period of time, have "scope" and may live only for the life of a method call. No threading issues.
- Instance class fields: Variables exist for the life of the class. Threading issues can come up if multiple threads go poking around.
- Static local variables: Variables are stored in a single location and are shared between instances. Threading issues galore as you are responsible for serializing access to folks messing with these variables.
- Variables marked with [ThreadStatic]: These should NEVER be used from within ASP.NET. I've blogged about its evil before. Details From MSDN - A static (Shared in Visual Basic) field marked with ThreadStaticAttribute is not shared between threads. Each executing thread has a separate instance of the field, and independently sets and gets values for that field. If the field is accessed on a different thread, it will contain a different value.
- CallContext: These are a set of properties that are carried along within the execution code path. You can add variables to the CallContext as it flows through execution. You can add objects into the CallContext as if it were a Hashtable, using .SetData() and .GetData(). As it moves over/between application domains, it is cloned. Objects that implement ILogicalThreadAffinative will go along for the ride.
- ThreadLocalStorage: This is something I don't see used a lot, as it's pretty specialized. Dino Chiesa had this cool example. He wanted to provide a factory that could be used by multiple threads to retrieve an object instance, but he wanted each thread to get their own reusable copy. He uses a LocalDataStoreSlot to store/cache objects on a thread-by-thread basis. This way he can always call GetProxy from his code, and ensure that only one copy will exist per thread.
public static System.LocalDataStoreSlot Slot= System.Threading.Thread.AllocateNamedDataSlot("webutil.proxy");
public static System.Net.WebProxy GetProxy()
object PutativeProxy = System.Threading.Thread.GetData(Slot);
string ProxyString = System.Configuration.ConfigurationSettings.AppSettings[GetConfigKey("proxy")];
if ((ProxyString == null) || (ProxyString == "")) return null;
PutativeProxy = new System.Net.WebProxy(ProxyString, true);
return (System.Net.WebProxy) PutativeProxy;