I have just hit something weird when I was exploring Threads and Tasks using ThreadStatic Attribute. I believe this may be very specific to Threads and Tasks. Consider the below code snippet:
[ThreadStatic]
static int range=10;
Action action = () =>
{Console.WriteLine("Thread = {0}, Value = {1}", Thread.CurrentThread.ManagedThreadId, range);
Parallel.Invoke( action, action);
This gives the output:
Thread = 2, Value = 10
Thread = 3, Value = 0
This is absolutely fine as ThreadStatic variables can only be initialized once and so, the second line shows it as 0.
But, consider the below scenario:
[ThreadStatic]
static int range=10;
new Thread(() =>
{
Console.WriteLine("Thread = {0}, Value = {1}" Thread.CurrentThread.ManagedThreadId, range);
}).Start();
new Thread(() =>
{
Console.WriteLine("Thread = {0}, Value = {1}" Thread.CurrentThread.ManagedThreadId, range);
}).Start();
This line gives me the output:
Thread = 6, Value = 0
Thread = 7, Value = 0
How much ever Thread I span, I couldn't really see the 'range' value being initialized and displayed as 10. Where is the range variable being initialized here and why there is discrimination between Threads and Tasks in initializing the static variables?
Am I missing something basic here ? Thanks in advance.
Your [ThreadStatic] is initialized by the static constructor of the class that contains this code. By the thread that creates the instance of the class or uses a static member, whichever is first. So by definition, the two new threads you create can never see the initial value.
The quirky behavior is actually in the first snippet. What you didn't count on is that Parallel.Invoke() also uses the thread that calls Invoke() to do part of the job. So it can actually see the initial value. Rewriting the code a bit can show you this:
class Test {
[ThreadStatic]
static int range=10;
public static void Run() {
Action action = () => {
Console.WriteLine("Thread = {0}, Value = {1}", Thread.CurrentThread.ManagedThreadId, range);
};
Console.WriteLine("Start thread = {0}, Value = {1}", Thread.CurrentThread.ManagedThreadId, range);
Parallel.Invoke(action, action);
}
}
Output:
Start thread = 8, Value = 10
Thread = 8, Value = 10
Thread = 9, Value = 0
Not a real problem of course, you can't use [ThreadStatic] in Parallel code.