Thread Local Storage

Static state is isolated on a per-application domain basis.

//each thread has its own copy of the field
[ThreadStatic] static int s_i;

The managed code abstraction that sits the closest to operating system primitives for thread-local storage is known as data slots.

// Initialization code.
LocalDataStoreSlot slot = Thread.AllocateNamedDataSlot(logger);
Thread.SetData(slot, new Logger() /* type definition omitted for brevity */);
// use
var slot = Thread.GetNamedDataSlot(logger);
var logger = (Logger)Thread.GetData(slot);
logger.WriteLine(Diagnostic message);

Closely related to the Lazy<T> class, the ThreadLocal<T> class was introduced in .NET 4. Essentially, this type addresses the shortcomings of the ThreadStatic attribute when initialization code is required for the per-thread state. The ThreadLocal<T> class acts as a factory for per-thread state, using a Func<T> delegate that’s invoked once per thread upon calling the Value property.

static ThreadLocal<TextWriter> s_log = new ThreadLocal<TextWriter>(() => {
    string name = Thread.CurrentThread.Name ?? Thread.CurrentThread.ManagedThreadId.ToString();
    // More complicated initialization logic could be dreamed up.
    // What matters is the fact this method will run multiple times  on different threads, initializing that thread’s logger.
    return File.CreateText(name + .log);
});