Raising an event thread safely

I'm sure I've seen this around before but I'm wondering how I should raise an event thread-safely.

I have a message despatch thread which looks somthing like.

while(_messages > 0){

    Message msg;
    // get next message

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

I can see that it may be posible for MessageDispatched to be come null after the check. from a MS blog I've seen:

var handler = MessageDispatched;

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

Which does stop the possibility of the reference becoming null after the check occurring. I'm wondering how to handle the case where the delegate is disposed (or even if it can?)

Should I just need to stick a try / catch around it, as its probably very rarely going to occur?

Edit

After reading answers I've considered making my class to handle this - quickly it looks something whats below, but I'm running into a few issues which make it not as clean as I want - maybe someone has an idea how to do that?

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

The latter structure will make sure you won't get a null reference exception calling the handler on non-Itanium architectures.

However, it leads to another possible issue -- it's possible for a client that registered an event handler to have the handler called after it's been removed. The only way to prevent that is to serialize raising the event and registering the handler. However, if you do that, you have a potential deadlock situation.

In short, there are three potential classes of ways this can break -- I go with the way you've done it here (and MS recommends) and accept that it is possible for an event handler to get called after it is unregistered.


从Eric Lippert阅读这篇文章:活动和比赛


请检查:在事件调度前检查null ...线程安全吗?

链接地址: http://www.djcxy.com/p/52934.html

上一篇: 应该将关键字添加到C#中以提升事件吗?

下一篇: 安全地提高事件线程