ThreadStatic vs ThreadLocal <T>: Ist generisch besser als Attribut?

94

[ThreadStatic]wird mit Attribut definiert, während ThreadLocal<T>generisch verwendet wird. Warum wurden unterschiedliche Designlösungen gewählt? Welche Vor- und Nachteile hat die Verwendung von generischen Überattributen in diesem Fall?

user2341923
quelle
4
Siehe reedcopsey.com/2009/11/12/… - Ich sehe nicht, was dies mit Reflexion zu tun hat ...
Jon Skeet

Antworten:

110

Etwas, das der Blog-Beitrag in den Kommentaren nicht explizit macht, aber ich finde es sehr wichtig, dass [ThreadStatic]es nicht automatisch Dinge für jeden Thread initialisiert. Angenommen, Sie haben Folgendes:

[ThreadStatic]
private static int Foo = 42;

Der erste Thread, der dies verwendet, wird auf Fooinitialisiert 42. Aber nachfolgende Threads werden nicht. Der Initialisierer funktioniert nur für den ersten Thread. Am Ende müssen Sie also Code schreiben, um zu überprüfen, ob er initialisiert ist.

ThreadLocal<T> Behebt dieses Problem, indem Sie eine Initialisierungsfunktion (wie Reeds Blog zeigt) bereitstellen, die vor dem ersten Zugriff auf das Element ausgeführt wird.

Meiner Meinung nach hat die Verwendung von [ThreadStatic]statt keinen Vorteil ThreadLocal<T>.

Jim Mischel
quelle
20
Außer vielleicht ThreadLocal<T>ist dies in .NET 4 und höher verfügbar, und das ThreadStaticAttribut ist auch in Version 3.5 und darunter verfügbar.
Jeroen
2
Wenn Sie den Wert nicht mit Initialisierern festlegen, sondern ihn zu einem späteren Zeitpunkt nach der Initialisierung festlegen, ist die Verwendung von [ThreadStatic] syntaktisch sauberer.
Dachte
9
Und außer das ThreadLocal<T>implementiert IDisposableund zwingt Sie normalerweise auch zur Implementierung IDisposable, was Ihre Anrufer dazu zwingt, Sie zu entsorgen und daher auch zu implementieren IDisposable...
Stefan Steinegger
4
@StefanSteinegger: Ich würde sehr vorsichtig mit ThreadLocaloder ThreadStaticmit Pool-Threads sein. Diese Werte bleiben während der gesamten Lebensdauer des Pool-Threads erhalten, nicht nur für die Aufgabe, die Sie ihm zuweisen. Das kann Ihnen auf ziemlich nicht offensichtliche Weise Probleme bereiten. Weitere Informationen finden Sie unter stackoverflow.com/questions/561518/… und ähnlichen Fragen.
Jim Mischel
3
Sollte das Feld im Beispiel nicht auch deklariert werden static? Siehe msdn.microsoft.com/en-us/library/…
am
39

ThreadStatic Initialize nur für den ersten Thread, ThreadLocal Initialize für jeden Thread. Unten ist die einfache Demonstration:

    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();
    }

Geben Sie hier die Bildbeschreibung ein

Marai
quelle
14

Die Hauptidee hinter ThreadStatic besteht darin, für jeden Thread eine separate Kopie der Variablen zu verwalten .

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();
        }
    }

Im obigen Snippet haben wir valuefür jeden Thread eine separate Kopie , einschließlich des Hauptthreads.

Geben Sie hier die Bildbeschreibung ein

Daher wird eine ThreadStatic-Variable in anderen Threads mit Ausnahme des Threads, in dem sie erstellt wurde, auf ihren Standardwert initialisiert.

Wenn wir die Variable für jeden Thread auf unsere eigene Weise initialisieren möchten, verwenden Sie ThreadLocal.

Sanjeev
quelle
1
Den vollständigen Artikel finden Sie hier .
Daniel Dušek