2011-01-06 3 views
6

Является ли этот метод расширения потоком безопасным?Безопасен ли метод расширения?

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); 
     } 
    } 
+0

дизайн и реализация детали событий в отношении потоковой обработки http://stackoverflow.com/questions/786383/c-events-and-thread-safety – user44298

ответ

9

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

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

+1

Я не уверен, что вы правы. Это применимо только тогда, когда вызывающая функция вызывала метод на значение, которое может быть изменено другим потоком (например, поле класса вместо локальной переменной). Я не знаю, включил бы JIT такой вызов в этом случае. – tster

+0

Однако это очень интересная тема. Хотел бы я, чтобы я не работал, и у меня было время вникать в это больше. – tster

+1

Ну, вот что такое нулевой тест в случае повышения кода. –

7

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

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

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

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

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

Смежные вопросы