安全地提升事件线程

时间:2009-11-25 08:53:57

标签: c# .net multithreading events

我确定我之前已经看过这个,但我想知道如何安全地提升一个事件。

我有一个消息发送线程看起来像。

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

这确实阻止了在检查发生后引用变为空的可能性。我想知道如何处理委托被处置的情况(或者即使它可以?)

我是否只需要坚持尝试/捕捉它,因为它很可能很少发生?

修改

在阅读完答案后,我考虑让我的班级来处理这个问题 - 很快就会看到下面的内容,但我遇到了一些问题,这些问题使得它不像我想要的那么干净 - 也许有人知道如何那样做?

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

3 个答案:

答案 0 :(得分:1)

后一种结构将确保您不会在非Itanium体系结构上调用处理程序时出现空引用异常。

但是,它会导致另一个可能的问题 - 注册事件处理程序的客户端可能会在被删除之后将处理程序称为。防止这种情况的唯一方法是序列化引发事件并注册处理程序。但是,如果这样做,则可能存在死锁情况。

简而言之,这有三种可能的方法可以解决 - 我采用你在这里完成它的方式(和MS推荐)并接受事件处理程序可能在它被调用之后被调用未注册的。

答案 1 :(得分:1)

阅读Eric Lippert的这篇文章:Events and Races

答案 2 :(得分:0)