[ThreadStatic]
определяется с помощью атрибута, а ThreadLocal<T>
использует общий. Почему были выбраны разные дизайнерские решения? Каковы преимущества и недостатки использования универсальных атрибутов в этом случае?
[ThreadStatic]
определяется с помощью атрибута, а ThreadLocal<T>
использует общий. Почему были выбраны разные дизайнерские решения? Каковы преимущества и недостатки использования универсальных атрибутов в этом случае?
Ответы:
Что-то в сообщении блога, отмеченном в комментариях, не говорится явным образом, но я считаю очень важным, это то, [ThreadStatic]
что не инициализируется автоматически для каждого потока. Например, скажем, у вас есть это:
[ThreadStatic]
private static int Foo = 42;
Первый поток, который его использует, будет Foo
инициализирован как 42
. Но последующих потоков не будет. Инициализатор работает только для первого потока. В итоге вам придется писать код, чтобы проверить, инициализирован ли он.
ThreadLocal<T>
решает эту проблему, позволяя вам предоставить функцию инициализации (как показывает блог Рида), которая запускается до первого доступа к элементу.
На мой взгляд, в использовании [ThreadStatic]
вместо ThreadLocal<T>
.
ThreadLocal<T>
доступно в .NET 4 и выше, а атрибут также доступен в версииThreadStatic
3.5 и ниже.
ThreadLocal<T>
реализует IDisposable
и обычно вынуждает вас реализовывать IDisposable
, что заставляет ваших вызывающих избавляться от вас и, следовательно, также реализовывать IDisposable
...
ThreadLocal
или ThreadStatic
с пула потоков. Эти значения будут оставаться в течение всего срока службы потока пула, а не только для задачи, которую вы ему назначаете. Это может доставить вам неприятности довольно неочевидными способами. См. Stackoverflow.com/questions/561518/… и аналогичные вопросы для получения дополнительной информации.
static
? См. Msdn.microsoft.com/en-us/library/…
ThreadStatic Initialize только в первом потоке, ThreadLocal Initialize для каждого потока. Ниже простая демонстрация:
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();
}
Основная идея 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.