ThreadStatic vs ThreadLocal <T>: le générique est-il meilleur que l'attribut?

95

[ThreadStatic]est défini à l'aide de l'attribut tandis que ThreadLocal<T>utilise générique. Pourquoi différentes solutions de conception ont-elles été choisies? Quels sont les avantages et les inconvénients de l'utilisation des attributs génériques dans ce cas?

user2341923
la source
4
Voir reedcopsey.com/2009/11/12 / ... - Je ne vois pas ce que cela a à voir avec la réflexion ...
Jon Skeet

Réponses:

112

Ce que l'article de blog noté dans les commentaires ne rend pas explicite, mais je trouve très important, c'est que cela [ThreadStatic]n'initialise pas automatiquement les choses pour chaque fil. Par exemple, disons que vous avez ceci:

[ThreadStatic]
private static int Foo = 42;

Le premier thread qui l'utilise verra Fooinitialisé à 42. Mais les fils suivants ne le seront pas. L'initialiseur fonctionne uniquement pour le premier thread. Vous finissez donc par devoir écrire du code pour vérifier s'il est initialisé.

ThreadLocal<T> résout ce problème en vous permettant de fournir une fonction d'initialisation (comme le montre le blog de Reed) qui est exécutée avant le premier accès à l'élément.

À mon avis, il n'y a aucun avantage à utiliser [ThreadStatic]au lieu de ThreadLocal<T>.

Jim Mischel
la source
20
Sauf peut-être que ThreadLocal<T>c'est disponible dans .NET 4 et plus, et l' ThreadStaticattribut est également disponible dans 3.5 et ci-dessous.
Jeroen
2
Et si vous n'utilisez pas d'initialiseurs pour définir la valeur, mais que vous la définissez plus tard après l'initialisation, l'utilisation de [ThreadStatic] est syntaxiquement plus propre.
Pensée le
9
Et sauf que cela ThreadLocal<T>implémente IDisposableet vous oblige généralement à implémenter IDisposableégalement, ce qui oblige vos appelants à vous éliminer et donc à implémenter IDisposableégalement ...
Stefan Steinegger
4
@StefanSteinegger: Je serais très prudent en utilisant ThreadLocalou ThreadStaticavec des threads de pool. Ces valeurs resteront pendant toute la durée de vie du thread de pool, pas seulement pour la tâche que vous lui attribuez. Cela peut vous causer des problèmes de manière assez peu évidente. Voir stackoverflow.com/questions/561518/… et des questions similaires pour plus d'informations.
Jim Mischel
3
Le champ de l'exemple ne devrait-il pas également être déclaré static? Voir msdn.microsoft.com/en-us/library/…
entheh
39

ThreadStatic Initialize uniquement sur le premier thread, ThreadLocal Initialize pour chaque thread. Voici la démonstration simple:

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

entrez la description de l'image ici

marai
la source
15

L'idée principale derrière ThreadStatic est de conserver une copie séparée de la variable pour chaque thread .

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

Dans l'extrait de code ci-dessus, nous avons une copie distincte de valuepour chaque thread, y compris le thread principal.

entrez la description de l'image ici

Ainsi, une variable ThreadStatic sera initialisée à sa valeur par défaut sur d'autres threads à l'exception du thread sur lequel elle est créée.

Si nous voulons initialiser la variable sur chaque thread à notre manière, utilisez ThreadLocal.

Sanjeev
la source
1
Et l'article complet peut être trouvé ici .
Daniel Dušek