【发布时间】: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