【问题标题】:Raising an event thread safely安全地引发事件线程
【发布时间】:2009-11-25 08:53:57
【问题描述】:

我确定我以前见过这种情况,但我想知道如何安全地引发事件。

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

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

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

我应该只需要在它周围加上一个 try/catch,因为它可能很少会发生吗?

编辑

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

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

【问题讨论】:

  • 您通过编辑添加的代码的问题可能是死锁。考虑一下:一个对象订阅了您的处理程序。在线程 A 上,获取了一个锁。在线程 B 上,发生了需要引发事件的事情。在处理程序中,它尝试获取线程 A 持有的锁,阻塞。然后线程 A 尝试在事件上注册一个处理程序,从而导致死锁(每个线程都持有另一个正在等待的锁)。恕我直言,这比其他任何一个问题都更糟糕(什么都不做的 NullRef,或者 MS 推荐方式的幻像事件)。

标签: c# .net multithreading events


【解决方案1】:

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

但是,这会导致另一个可能的问题——注册了事件处理程序的客户端可能会在删除事件处理程序后调用处理程序。防止这种情况的唯一方法是序列化引发事件并注册处理程序。但是,如果这样做,您可能会出现死锁情况。

简而言之,这可能会破坏三种潜在的方式——我采用您在此处所做的方式(MS 建议)并接受事件处理程序可能在它被调用之后被调用未注册。

【讨论】:

    【解决方案2】:
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多