ThreadStatic vs ThreadLocal <T>: é genérico melhor que atributo?

95

[ThreadStatic]é definido usando atributo enquanto ThreadLocal<T>usa genérico. Por que diferentes soluções de design foram escolhidas? Quais são as vantagens e desvantagens de usar atributos genéricos em vez de atributos neste caso?

user2341923
fonte
4
Veja reedcopsey.com/2009/11/12/… - Não vejo o que isso tem a ver com reflexão ...
Jon Skeet

Respostas:

112

Algo que o post do blog anotado nos comentários não deixa explícito, mas acho muito importante, é que [ThreadStatic]não inicializa as coisas automaticamente para cada tópico. Por exemplo, digamos que você tenha este:

[ThreadStatic]
private static int Foo = 42;

O primeiro thread que usar isso será Fooinicializado como 42. Mas os tópicos subsequentes não. O inicializador funciona apenas para o primeiro thread. Então você acaba tendo que escrever código para verificar se ele foi inicializado.

ThreadLocal<T> resolve esse problema permitindo que você forneça uma função de inicialização (como mostra o blog de Reed) que é executada antes da primeira vez que o item é acessado.

Em minha opinião, não há vantagem em usar em [ThreadStatic]vez de ThreadLocal<T>.

Jim Mischel
fonte
20
Exceto, talvez, que ThreadLocal<T>esteja disponível no .NET 4 e superior, e o ThreadStaticatributo também está disponível no 3.5 e abaixo.
Jeroen
2
E se você não estiver usando inicializadores para definir o valor, mas em vez disso, está definindo-o em algum ponto posterior após a inicialização, usar [ThreadStatic] é sintaticamente mais limpo.
Pensei em
9
E exceto que ThreadLocal<T>implementa IDisposablee geralmente força você a implementar IDisposabletambém, o que força seus chamadores a descartá-lo e, portanto, implementar IDisposabletambém ...
Stefan Steinegger
4
@StefanSteinegger: Eu teria muito cuidado ao usar ThreadLocalou ThreadStaticcom threads de pool. Esses valores permanecerão por toda a vida útil do thread do pool, não apenas para a tarefa que você atribui. Isso pode causar problemas de maneiras nada óbvias. Consulte stackoverflow.com/questions/561518/… e perguntas semelhantes para obter mais informações.
Jim Mischel
3
O campo no exemplo também não deveria ser declarado static? Consulte msdn.microsoft.com/en-us/library/…
entheh
39

ThreadStatic Initialize apenas no primeiro thread, ThreadLocal Initialize para cada thread. Abaixo está a demonstração simples:

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

insira a descrição da imagem aqui

marai
fonte
15

A ideia principal por trás do ThreadStatic é manter uma cópia separada da variável para cada 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();
        }
    }

No snippet acima, temos uma cópia separada de valuepara cada tópico, incluindo o tópico principal.

insira a descrição da imagem aqui

Portanto, uma variável ThreadStatic será inicializada com seu valor padrão em outras threads, exceto na thread em que foi criada.

Se quisermos inicializar a variável em cada thread à nossa maneira, use ThreadLocal.

Sanjeev
fonte
1
E o artigo completo pode ser encontrado aqui .
Daniel Dušek