Occasionally you might want to make the value of a static or instance field local to a thread (i.e. each thread holds an independent copy of the field), what you need in this case, is a thread-local storage.
In C#, there are mainly two ways to do this.
ThreadStatic
You can mark a field with the ThreadStatic attribute:
<br /> [ThreadStatic]<br /> public static int _x;<br /> …<br /> Enumerable.Range(1, 10).Select(i => new Thread(() => Console.WriteLine(_x++))).ToList()<br /> .ForEach(t => t.Start()); // prints 0 ten times<br />
Whilst this is the easiest way to implement thread-local storage in C# it’s important to understand the limitations here:
- the ThreadStatic attribute doesn’t work with instance fields, it compiles and runs but does nothing..
<br /> [ThreadStatic]<br /> public int _x;<br /> …<br /> Enumerable.Range(1, 10).Select(i => new Thread(() => Console.WriteLine(_x++))).ToList()<br /> .ForEach(t => t.Start()); // prints 0, 1, 2, … 9<br />
- field always start with the default value
<br /> [ThreadStatic]<br /> public static int _x = 1;<br /> …<br /> Enumerable.Range(1, 10).Select(i => new Thread(() => Console.WriteLine(_x++))).ToList()<br /> .ForEach(t => t.Start()); // prints 0 ten times<br />
ThreadLocal<T>
C# 4 has introduced a new class specifically for the thread-local storage of data – the ThreadLocal<T> class:
<br /> private readonly ThreadLocal<int> _localX = new ThreadLocal<int>(() => 1);<br /> …<br /> Enumerable.Range(1, 10).Select(i => new Thread(() => Console.WriteLine(_localX++))).ToList()<br /> .ForEach(t => t.Start()); // prints 1 ten times<br />
There are some bonuses to using the ThreadLocal<T> class:
- values are lazily evaluated, the factory function evaluates on the first call for each thread
- you have more control over the initialization of the field and is able to initialize the field with a non-default value
Summary
As you can see, using ThreadLocal<T> has some clear advantages over ThreadStatic, though using 4.0 only features like ThreadLocal<T> means you have to target your project at the .Net 4 framework and is therefore not backward compatible with previous versions of the framework.
It’s also worth noting that besides ThreadLocal<T> and ThreadStatic you can also use Thread.GetData and Thread.SetData to fetch and store thread specific data from and to a named LocalDataStoreSlot though this is usually cumbersome…
Great post!
Thank you for your clear explanation.
One question about 4th block of code. Shouldn’t be _localX.Value++ there?
With your code compiler says Operator ‘++’ cannot be applied to operand of type ‘System.Threading.ThreadLocal”
Best regards,
Grzegorz
Hi,
What’s with the ‘readonly’ on the
‘private readonly ThreadLocal _localX = new ThreadLocal(() => 1);’
Wow! Nice one, busy with my C# exam 70-486. This is explained so well.
Sorry meant to say exam 70-483
This ensures that _localX can never be modified after it is assigned.