Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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();
        }
    }
}
like image 312
HedgePig Avatar asked Nov 07 '16 10:11

HedgePig


People also ask

What is __ thread in C?

The __thread storage class marks a static variable as having thread-local storage duration. This means that in a multi-threaded application a unique instance of the variable is created for each thread that uses it and destroyed when the thread terminates.

Is ThreadLocal thread-safe?

Thread Safety With the exception of Dispose(), all public and protected members of ThreadLocal<T> are thread-safe and may be used concurrently from multiple threads.

What is thread-local storage C#?

Thread-local storage (TLS) is a computer programming method that uses static or global memory local to a thread. All threads of a process share the virtual address space of the process. The local variables of a function are unique to each thread that runs the function.

Can ThreadLocal cause memory leak?

ThreadLocal variables are infamous for creating memory leaks. A memory leak in Java is the amount of memory hold by an object which is not in use and should have been garbage collected, but because of unintended strong references, they still live in Java heap space.


1 Answers

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);
}
like image 142
Evk Avatar answered Sep 26 '22 16:09

Evk