Является ли метод расширения поток безопасным? - PullRequest
6 голосов
/ 06 января 2011

Этот метод расширения безопасен для потока?

   public static class Extensions
   {
      public static void Raise<T>(this EventHandler<T> handler,
        object sender, T args) where T : EventArgs
      {
         if (handler != null) handler(sender, args);
      }
   }

или мне нужно изменить это на это?

   public static class Extensions
   {
      public static void Raise<T>(this EventHandler<T> handler,
        object sender, T args) where T : EventArgs
      {
         var h = handler;
         if (h!= null) h(sender, args);
      }
   }

Ответы [ 2 ]

9 голосов
/ 06 января 2011

Вы нашли интересную дыру в петле, она всех сбила с толку. Нет, это не потокобезопасно.

Хотя выглядит , как ссылка EventHandler <> копируется через аргумент метода, это не то, что происходит во время выполнения. Методы расширения могут быть встроены, как обычный метод экземпляра. На самом деле, он чрезвычайно может оказаться встроенным, поскольку он очень мал. Там нет копии, вы должны сделать ее самостоятельно.

7 голосов
/ 07 января 2011

Ни одна из версий не является потокобезопасной, в зависимости от того, что вы подразумеваете под "потокобезопасностью".Рассмотрим вторую версию:

   var h = handler;          
   if (h!= null) 
       h(sender, args);

«Обработчик» - это копия некоторого поля, в котором есть неизменный делегат.Предположим, что поле проверяется на «ноль» в другом потоке после проверки на ноль.В этом случае ваш код не падает, потому что вы сделали копию исходного ненулевого значения.Но просто без сбоев не делает программу поточно-безопасной .Программа, которая не аварийно завершает работу, но по-прежнему выдает неправильные результаты, по-прежнему не является поточно-ориентированной.

Предположим, что когда другой поток установил в поле события значение null, он также изменил состояние, в котором предыдущее содержимое должно было работать правильно.Теперь вы собираетесь запустить обработчик событий, который зависит от состояния, которое только что было изменено в другом потоке;вы используете устаревший обработчик событий.

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

...