2009-11-25 4 views
2

Я уверен, что видел это раньше, но мне интересно, как я должен поднимать потоки событий - безопасно.Безопасное создание потока событий

У меня есть поток сообщений, который выглядит чем-то вроде.

while(_messages > 0){ 

    Message msg; 
    // get next message 

    if (MessageDispatched != null) 
     MessageDispatched(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params)); 
} 

Я могу видеть, что это может быть для MessageDispatched Возможное чтобы прийти нуль после проверки. из блога MS, который я видел:

var handler = MessageDispatched; 

if (handler != null) 
    handler(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params)); 

Который останавливает возможность обращения ссылки к нулю после проверки. Мне интересно, как обрабатывать случай, когда делегат находится (или даже если он может?)

Должен ли я просто придерживаться попытки/поймать его, так как его, вероятно, очень редко произойдет?

Редактировать

После прочтения ответов я думал сделать свой класс, чтобы справиться с этим - быстро это выглядит WHATS ниже, но я бег в нескольких вопросов, которые делают его не так чисты, как я хочу - может быть, у кого-то есть идея, как это сделать?

public class ThreadSafeEvent<TDelegate> 
// where TDelegate : Delegate  why is this a non allowed special case??? 
{ 
    List<TDelegate> _delegates = new List<TDelegate>(); 

    public void Subscribe(TDelegate @delegate) 
    { 

     lock (_delegates) 
     { 
      if (!_delegates.Contains(@delegate)) 
       _delegates.Add(@delegate); 
     } 
    } 

    public void Unsubscibe(TDelegate @delegate) 
    { 
     lock (_delegates) 
     { 
      _delegates.Remove(@delegate); 
     } 
    } 


    // How to get signature from delegate? 
    public void Raise(params object[] _params) 
    { 
     lock (_delegates) 
     { 
      foreach (TDelegate wrappedDel in _delegates) 
      { 
       var del = wrappedDel as Delegate; 
       del.Method.Invoke (del.Target, _params); 
      } 
     } 
    } 
} 
+1

Проблемы с кодом добавленным с помощью редактирования возможного тупика. Рассмотрим это: объект подписывается на ваш обработчик. В потоке A получен замок. В потоке B происходит что-то, что требует, чтобы событие было поднято. В обработчике для этого он пытается получить блокировку, удерживаемую нитью A, блокируя. Затем поток A пытается зарегистрировать обработчик события, что приводит к тупиковой ситуации (каждый поток содержит блокировку, которую ожидает другой). ИМХО, это хуже, чем любая другая проблема (NullRef ничего не делает, или фантомное событие из рекомендованного MS). –

ответ

1

Последняя структура будет убедиться, что вы не получите ссылку на нулевой исключение вызывающего обработчик на не Itanium архитектуры.

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

Короче говоря, есть три возможных класса способов, которыми это может сломаться - я иду так, как вы это сделали (и рекомендует MS), и соглашайтесь с тем, что обработчик события можно вызвать после него не зарегистрировано.

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