[ThreadStatic]
est défini en utilisant 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 de génériques par rapport aux attributs dans ce cas?
Quelque chose que le billet de blog noté dans les commentaires ne rend pas explicite, mais je trouve très important, c'est que [ThreadStatic]
n'initialise pas automatiquement les choses pour chaque thread. Par exemple, disons que vous avez ceci:
[ThreadStatic]
private static int Foo = 42;
Le premier thread qui utilise ceci verra Foo
initialisé à 42
. Mais les threads suivants ne le seront pas. L'initialiseur fonctionne uniquement pour le premier thread. Vous finissez donc par avoir à é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>
.
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();
}
L'idée principale derrière ThreadStatic est de maintenir 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 ci-dessus, nous avons une copie distincte de value
pour chaque thread, y compris le thread principal.
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.