线程安全和异常捕获事件
本文关键字:事件 异常 安全 线程 | 更新日期: 2023-09-27 18:11:21
我使用了下面的例子来执行事件:
try
{
if (this.onClientConnected != null)
this.onClientConnected(this, new EventArgs());
}
catch (Exception e)
{
//log and handle exception
}
但是这当然有一些缺点,比如如果一个订阅的委托抛出异常,其余的不会被执行,因为我在多线程应用程序中使用它,在检查null和抛出事件之间,有人可以取消订阅,抛出null异常。
现在我研究了一种更好的方式来抛出这些事件,并提出了这个:
Delegate[] methods = this.onClientConnected.GetInvocationList();
methods.ToList().ForEach(x =>
{
try
{
x.DynamicInvoke(this, new EventReceivedEventArgs(Trigger.TriggerName, Trigger.InstanceID, Trigger.Parameters, Trigger.SourceIpAddress));
}
catch (Exception e)
{
//log and handle exception
}
});
这是一个好方法,或者有一个更好的方法来处理多线程事件与异常?
是否可以通过在同一线程中运行所有的add/remove属性访问,或者在正确的抽象级别上使用锁来序列化所有的订阅/取消订阅逻辑?请看Stephen Toub关于这个话题的讨论。
我将把事件中的多播委托缓存到一个局部变量中,检查它,然后"调用"它。参见Eric Lippert对该主题的讨论。
考虑在任务中包装事件,正如Igor Ostrovsky在MSDN文章中所描述的那样。这是TPL路线…
例如(我引用):
static Task<string> DownloadStringAsTask(Uri address) {
TaskCompletionSource<string> tcs =
new TaskCompletionSource<string>();
WebClient client = new WebClient();
client.DownloadStringCompleted += (sender, args) => {
if (args.Error != null) tcs.SetException(args.Error);
else if (args.Cancelled) tcs.SetCanceled();
else tcs.SetResult(args.Result);
};
client.DownloadStringAsync(address);
return tcs.Task;
}
在计算返回的Task的任何地方都可以观察到异常,例如使用。result或。wait()。
考虑通过同一线程进行事件处理。例如,使用. continuewith()重载,它接受一个调度程序,该调度程序总是向UI线程发送消息。
最后,Rx是事件的另一个很好的替代方案。