﻿# V3089\. Initializer of a field marked by \[ThreadStatic\] attribute will be called once on the first accessing thread\. The field will have default value on different threads\.

Анализатор обнаружил подозрительный фрагмент кода, в котором поле, отмеченное атрибутом \[ThreadStatic\] инициализируется при объявлении или в статическом конструкторе\. 

Если выполняется инициализация при объявлении, поле будет проинициализировано этим значением только у первого обратившегося потока\. В остальных потоках это поле будет содержать значение, предусмотренное по умолчанию\.

Схожая ситуация со статическим конструктором – он выполняется только один раз, и поле будет проинициализировано только в потоке, в котором статический конструктор выполнится\.

Рассмотрим пример ситуации с инициализацией при объявлении:

```cpp
class SomeClass
{
  [ThreadStatic]
  public static Int32 field = 42;
}

class EntryPoint
{
  static void Main(string[] args)
  {
    new Task(() => { var a = SomeClass.field; }).Start(); // a == 42
    new Task(() => { var a = SomeClass.field; }).Start(); // a == 0
    new Task(() => { var a = SomeClass.field; }).Start(); // a == 0
  }
}
```

При обращении первого потока к полю 'field' оно будет проинициализировано заданным программистом значением\. Таким образом, переменная 'a' будет иметь значение '42', равно как и поле 'field'\.

При запуске последующих потоков и обращении к полю, оно уже будет проинициализировано значением по умолчанию \('0' в данном случае\), поэтому во всех последующих потоков значение 'a' будет равно '0'\.

Как упоминалось ранее, статический конструктор не является решением проблемы – он будет вызван 1 раз, при инициализации типа, поэтому проблема остаётся актуальной\.

Решением может послужить использование свойства в качестве обёртки над полем, куда можно дописать дополнительную логику по инициализации поля\. Это решает проблему, но опять же, не полностью – при обращении к полю, а не свойству \(например, внутри класса\), остаётся вероятность получить некорректное значение\.

```cpp
class SomeClass
{
  [ThreadStatic]
  private static Int32 field = 42;

  public static Int32 Prop
  {
    get
    {
      if (field == default(Int32))
        field = 42;

      return field;
    }

    set
    {
      field = value;
    }
  }
}
class EntryPoint
{
  static void Main(string[] args)
  {
    new Task(() => { var a = SomeClass.Prop; }).Start(); // a == 42
    new Task(() => { var a = SomeClass.Prop; }).Start(); // a == 42
    new Task(() => { var a = SomeClass.Prop; }).Start(); // a == 42
  }
}
```