HedgePig HedgePig - 1 month ago 8
C# Question

ThreadLocal <T> - What is a thread? (C#)

I'm struggling with multithreading in C# (which I'm learning just for fun) and realise I probably don't understand what a thread is! When I run the code below, I was expecting to get something like the following output.

T1: 11
T2: 11
T3: 11
T4: 11
T5: 11
T6: 11


(possibly in a different order)

However, I'm getting something like

T1: 11
T2: 11
T3: 12
T5: 12
T6: 13
T4: 11


I had assumed that each task (T1 to T6) would be a new thread and therefore each instance of "local" would be initialised to 10 and incremented by one. But it certainly doesn't look like this is happening. If anyone can explain what is going on and what I am incorrectly assuming, I'd be very grateful.
(I must admit I'm finding it difficult to come to grips with threading because I can't find anything basic enough to start from!)

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{

class TestThreadLocal
{

static void Main()
{
ThreadLocal<int> local = new ThreadLocal<int>(() =>
{ return 10;
});

Task t1 = Task.Run(() =>
{ local.Value++;
Console.WriteLine("T1: " + local.Value);
});

Task t2 = Task.Run(() =>
{ local.Value++;
Console.WriteLine("T2: " + local.Value);
});
Task t3 = Task.Run(() =>
{ local.Value++;
Console.WriteLine("T3: " + local.Value);
});

Task t4 = Task.Run(() =>
{ local.Value++;
Console.WriteLine("T4: " + local.Value);
});

Task t5 = Task.Run(() =>
{ local.Value++;
Console.WriteLine("T5: " + local.Value);
});

Task t6 = Task.Run(() =>
{ local.Value++;
Console.WriteLine("T6: " + local.Value);
});

Task.WaitAll(t1, t2, t3, t4, t5, t6);
local.Dispose();
}
}
}

Evk Evk
Answer

The reason is Task.Run uses thread pool, which means it grabs some free thread from the pool of already existing threads, does work on it, and returns it back (in simplified terms). So it's perfectly possible that one or more of subsequent Tas.Run operations will run on the same thread. Easiest way to verify it is to print current thread id:

Task.Run(() => {
   local.Value++;
   Console.WriteLine("Thread id: {0}, value: {1}", Thread.CurrentThread.ManagedThreadId, local.Value);
}