ThreadStatic v.s. ThreadLocal <T>: более общий, чем атрибут?

[ThreadStatic] определяется с использованием атрибута, а ThreadLocal<T> использует общий. Почему были выбраны различные дизайнерские решения? Каковы преимущества и недостатки использования общих атрибутов в этом случае?

Ответ 1

То, что сообщение в блоге, отмеченное в комментариях, не делает явным, но я считаю очень важным, что [ThreadStatic] автоматически не инициализирует вещи для каждого потока. Например, скажите, что у вас есть это:

[ThreadStatic]
private static int Foo = 42;

Первый поток, который использует это, увидит, что Foo инициализирован до 42. Но последующих потоков не будет. Инициализатор работает только для первого потока. Поэтому вам нужно написать код, чтобы проверить, инициализирован ли он.

ThreadLocal<T> решает эту проблему, предоставляя вам функцию инициализации (как показывает блог Рида), которые запускаются до того, как первый элемент доступа будет доступен.

На мой взгляд, нет преимущества использовать [ThreadStatic] вместо ThreadLocal<T>.

Ответ 2

ThreadStatic Инициализировать только в первом потоке, ThreadLocal Инициализировать для каждого потока. Ниже приведена простая демонстрация:

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

enter image description here

Ответ 3

Основная идея ThreadStatic - поддерживать отдельную копию переменной для каждого потока.

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

В приведенном выше фрагменте у нас есть отдельная копия value для каждого потока, включая основной поток.

введите описание изображения здесь

Итак, переменная ThreadStatic будет инициализирована значением по умолчанию для других потоков, кроме потока, на котором она создана.

Если мы хотим инициализировать переменную в каждом потоке по-своему, используйте ThreadLocal.

Ответ 4

Я использую оба в одном месте, потому что ThreadStatic Инициализируется только в первом потоке, ThreadLocal Initialize для каждого потока.

[ThreadStatic]
    private static IOperationHolder<RequestTelemetry> operation;

    private ThreadLocal<bool> status = new ThreadLocal<bool>(true);

    //TODO: this method will move AOP start method
    public void StartOperation(string functionName)
    {
        RequestTelemetry requestTelemetry = new RequestTelemetry { Name = functionName };
        operation = telemetryClient.StartOperation(requestTelemetry);
    }