Обработчики событий не являются потокобезопасными?
Итак, я прочитал, что вместо прямого вызова события
if (SomeEvent != null)
SomeEvent(this, null);
Я должен делать
SomeEventHandler temp = SomeEvent;
if (temp != null)
temp(this, null);
Почему это так? Как вторая версия становится потокобезопасной? Какова наилучшая практика?
Ответы
Ответ 1
События - это действительно синтаксический сахар над списком делегатов. Когда вы вызываете событие, это действительно перебирает этот список и вызывает каждого делегата с параметрами, которые вы передали.
Проблема с потоками заключается в том, что они могут добавлять или удалять элементы из этой коллекции, подписываясь/отменяя подписку. Если они делают это во время итерации коллекции, это вызовет проблемы (я думаю, что исключение выбрано)
Цель состоит в том, чтобы скопировать список перед его итерацией, поэтому вы защищены от изменений в списке.
Примечание. Теперь вы можете активировать прослушиватель даже после того, как вы отменили подписку, поэтому вы должны убедиться, что вы справляетесь с этим в своем коде слушателя.
Ответ 2
IMO, другие ответы пропускают одну ключевую деталь - делегаты (и, следовательно, события) неизменяемы. Значимость этого заключается в том, что подписка или отмена подписки на обработчик событий не просто добавляются/удаляются в список - скорее, он заменяет список новым с дополнительным (или одним меньшим) элементом на нем.
Поскольку ссылки являются атомарными, это означает, что в той точке, которую вы делаете:
var handler = SomeEvent;
теперь у вас есть жесткий экземпляр, который не может измениться, даже если в следующий пикосекунд другой поток отменит подписку (чтобы фактическое поле события стало null
).
Итак, вы проверяете значение null и вызываете его, и все хорошо. Обратите внимание, конечно, что все еще запутанный сценарий события, возникающего на объекте, который считает, что он отменил пикосекунд назад!
Ответ 3
Лучшей практикой является вторая форма. Причина в том, что другой поток может обнулить или изменить SomeEvent
между тестом 'if
' и вызовом.
Ответ 4
Здесь хорошая запись о событиях .NET и условиях гонки с потоками. Он охватывает некоторые распространенные сценарии и содержит несколько хороших ссылок.
Надеюсь, что это поможет.