ThreadStatic vs ThreadLocal <T>: czy ogólny lepszy niż atrybut?


Odpowiedzi:


114

Coś, co we wpisie na blogu odnotowano w komentarzach, nie jest jednoznaczne, ale uważam za bardzo ważne, to to, że [ThreadStatic]nie inicjuje automatycznie rzeczy dla każdego wątku. Na przykład powiedz, że masz to:

[ThreadStatic]
private static int Foo = 42;

Pierwszy wątek, który to używa, zostanie Foozainicjowany 42. Ale kolejne wątki już nie. Inicjator działa tylko dla pierwszego wątku. W końcu musisz napisać kod, aby sprawdzić, czy jest zainicjowany.

ThreadLocal<T> rozwiązuje ten problem, pozwalając ci podać funkcję inicjalizacyjną (jak pokazuje blog Reeda), która jest uruchamiana przed pierwszym dostępem do elementu.

Moim zdaniem nie ma żadnej korzyści z używania [ThreadStatic]zamiast ThreadLocal<T>.


20
Z wyjątkiem być może, że ThreadLocal<T>jest dostępny w .NET 4 iw górę, a atrybut dostępny w 3,5 i poniżej jest również. ThreadStatic
Jeroen,

2
A jeśli nie używasz inicjatorów do ustawiania wartości, ale zamiast tego ustawiasz ją później po inicjalizacji, użycie [ThreadStatic] jest składniowo czystsze.
pomyślał

9
I poza tym, że ThreadLocal<T>wdraża IDisposablei zwykle zmusza cię do implementacji IDisposable, co zmusza twoich rozmówców do pozbycia się ciebie, a zatem również implementacji IDisposable...
Stefan Steinegger

4
@StefanSteinegger: Byłbym bardzo ostrożny używając ThreadLocallub ThreadStaticz wątkami puli. Te wartości pozostaną przez cały czas życia wątku puli, a nie tylko dla zadania, które mu przydzielisz. Może to powodować kłopoty na dość nieoczywiste sposoby. Aby uzyskać więcej informacji, zobacz stackoverflow.com/questions/561518/ ... i podobne pytania.
Jim Mischel

3
Czy pole w przykładzie nie powinno być również zadeklarowane static? Zobacz msdn.microsoft.com/en-us/library/…
entheh

39

ThreadStatic Zainicjuj tylko w pierwszym wątku, ThreadLocal Zainicjuj dla każdego wątku. Poniżej znajduje się prosta demonstracja:

    public static ThreadLocal<int> _threadlocal =
        new ThreadLocal<int>(() =>
        {
            return Thread.CurrentThread.ManagedThreadId;
        });

    public static void Main()
    {
        new Thread(() =>
        {
            for (int x = 0; x < _threadlocal.Value; x++)
            {
                Console.WriteLine("First Thread: {0}", x);
            }
        }).Start();

        new Thread(() =>
        {
            for (int x = 0; x < _threadlocal.Value; x++)
            {
                Console.WriteLine("Second Thread: {0}", x);
            }
        }).Start();

        Console.ReadKey();
    }

wprowadź opis obrazu tutaj


16

Główną ideą stojącą za ThreadStatic jest utrzymywanie oddzielnej kopii zmiennej dla każdego wątku .

class Program
    {
        [ThreadStatic]
        static int value = 10;

        static void Main(string[] args)
        {
            value = 25;

            Task t1 = Task.Run(() =>
            {
                value++;
                Console.WriteLine("T1: " + value);
            });
            Task t2 = Task.Run(() =>
            {
                value++;
                Console.WriteLine("T2: " + value);
            });
            Task t3 = Task.Run(() =>
            {
                value++;
                Console.WriteLine("T3: " + value);
            });

            Console.WriteLine("Main Thread : " + value);

            Task.WaitAll(t1, t2, t3);
            Console.ReadKey();
        }
    }

W powyższym fragmencie mamy oddzielną kopię valuedla każdego wątku, w tym wątku głównego.

wprowadź opis obrazu tutaj

Tak więc zmienna ThreadStatic zostanie zainicjowana do wartości domyślnej w innych wątkach, z wyjątkiem wątku, w którym została utworzona.

Jeśli chcemy zainicjować zmienną w każdym wątku na swój własny sposób, użyj ThreadLocal.


1
Cały artykuł można znaleźć tutaj .
Daniel Dušek,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.