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

96

[ThreadStatic]jest definiowany przy użyciu atrybutu, podczas gdy ThreadLocal<T>używa generic. Dlaczego wybrano różne rozwiązania projektowe? Jakie są zalety i wady używania atrybutów ogólnych zamiast atrybutów w tym przypadku?

user2341923
źródło
4
Zobacz reedcopsey.com/2009/11/12/… - Nie rozumiem jednak, co to ma wspólnego z refleksją ...
Jon Skeet

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>.

Jim Mischel
źródło
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

marai
źródło
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.

Sanjeev
źródło
1
Cały artykuł można znaleźć tutaj .
Daniel Dušek,