Изменение значения потока c при утилизации не работает с асинхронным - PullRequest
0 голосов
/ 27 марта 2020

Может быть, код, начинающийся с кода, будет проще сформулировать вопрос:

 public class RecorderScope : IDisposable
    {
        [ThreadStatic]
        private static RecorderScope current;

        public static RecorderScope Current => current;

        public RecorderScope()
        {        
            if (current != null) throw new Exception("usually by design, don't make complex stuff");
            current = this;
        }

        public void Dispose()
        {
            current = null;
        }
    }

Это означает, что какой-то другой класс может проверить, используется ли он в RecorderScope, и что-то сделать с этим фактом. Он используется только в модульных тестах, предназначен для простых случаев, поэтому мне нет дела до вложенности, и т. Д. c. - но модульные тесты могут выполняться параллельно, следовательно, [ThreadStatic].

Теперь он работает нормально, пока в этой области нет ожидания. Я сделал некоторые записи и, похоже, проблема в том, что в конструктор приходит поток с идентификатором x, а для удаления приходит поток с идентификатором y (как и ожидалось, именно так работает асин c), следовательно, значение потока x остается не утилизированным.

Есть идеи как это исправить?

1 Ответ

2 голосов
/ 28 марта 2020

Теперь все работает нормально, пока в этой области нет ожидания ... Есть идеи, как это исправить?

Да. Вы действительно не должны использовать ThreadStatic в современном коде вообще. Вместо этого используйте AsyncLocal<T>:

public class RecorderScope : IDisposable
{
  private static AsyncLocal<RecorderScope> current;

  public static RecorderScope Current => current.Value;

  public RecorderScope()
  {        
    if (Current != null) throw new Exception("usually by design, don't make complex stuff");
    Current.Value = this;
  }

  public void Dispose()
  {
    Current.Value = null;
  }
}

У меня есть сообщение в блоге , в которое входит более семанти c подробностей (написанных до того, как AsyncLocal<T> существовал).

Одно важное замечание, которое недостаточно документировано с помощью AsyncLocal<T>, заключается в том, что вы всегда должны обновлять значение, устанавливая свойство Value, а не изменяя объект T. В идеале, T должен быть неизменным, но в данном конкретном случае (поскольку Value устанавливается только тогда, когда null, а позже устанавливается только на null, никогда не обновляется), неизменность не требуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...