Подтвердить что ты не робот

Добавить делегат в безопасность событий - потоков

Можно выполнить следующий код из нескольких потоков одновременно.

this._sequencer.Completed += OnActivityFinished;

Можно ли потокобезопасно добавлять делегат в обработчик событий из нескольких потоков?

Безопасно ли потоковое удаление делегата из обработчика событий из нескольких потоков?

Каков самый простой и удобный способ обеспечения безопасности этого потока?

4b9b3361

Ответ 1

Если вы не указали свои собственные обработчики добавления/удаления событий, компилятор С# генерирует этот add handler (реконструированный .NET Reflector):

public void add_MyEvent(EventHandler value)
{
    EventHandler handler2;
    EventHandler myEvent = this.MyEvent;
    do
    {
        handler2 = myEvent;
        EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value);
        myEvent = Interlocked.CompareExchange<EventHandler>(ref this.MyEvent, handler3, handler2);
    }
    while (myEvent != handler2);
}

и удалить обработчик, который выглядит так же, но с Delegate.Remove вместо Delegate.Combine.

Обратите внимание на использование Interlocked.CompareExchange? Это предотвращает условие гонки между обновлением поля поддержки событий и чтением из него. Таким образом, он является потокобезопасным.

Ответ 2

для полевых событий Добавление/удаление обработчиков является потокобезопасным. Из спецификации:

При компиляции полевого события компилятор автоматически создает хранилище для хранения делегата и создает аксессоры для события, которые добавляют или удаляют обработчики событий в поле делегата. Чтобы быть потокобезопасными, операции добавления или удаления выполняются при удерживании блокировки (§8.12) для объекта-объекта для события экземпляра или объекта типа (§7.6.10.6) для статического события.

Однако это верно для С# 3.0 и меньше, в компиляторе С# 4.0 генерируется незаблокированная реализация с использованием блокированных подпрограмм (но спецификация остается той же - ошибка?)

В пользовательских реализациях никто не может точно сказать... кроме, может быть, автора кода:)

Ответ 3

Это зависит от реализации мероприятия, если честно.

Полевые события, генерируемые компилятором С#, являются потокобезопасными, но если это пользовательское событие, кто знает?

Обратите внимание, что в многопоточном приложении вы должны ожидать условия гонки между добавлением/удалением обработчика и запуском события... например, событие может начать срабатывать, вы можете отказаться от подписки, и ваш обработчик все равно будет после этого отменяется подписка.