gpt4 book ai didi

wpf - 捕获线程、任务、计时器、ThreadPool 线程和后台工作线程上引发的 UnhandledExceptions

转载 作者:行者123 更新时间:2023-12-01 21:24:16 25 4
gpt4 key购买 nike

我有一个 WPF C# 4.0 应用程序,用于调查未处理的异常处理。我希望代码中只有一个位置可以处理任何线程上引发的未处理的异常,无论线程是如何创建的。在我的 App.xaml.cs 文件中,我有这些未处理的异常处理程序,它们向控制台发出消息:

public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

AppDomain.CurrentDomain.UnhandledException += this.CurrentDomain_UnhandledException;
Application.Current.DispatcherUnhandledException += this.Current_DispatcherUnhandledException;
}

void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
Console.WriteLine("Current_DispatcherUnhandledException");
e.Handled = true;
}

void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("CurrentDomain_UnhandledException");
}
}

我有一个 WPF 窗口,上面有五个按钮,它们以五种不同的方式启动线程:任务、线程、线程池、BackgroundWorker 和 System.Threading.Timer。每次单击按钮的代码分别启动一个新任务、线程等,并在新线程上抛出 NotImplementedException。在某些情况下,异常会被捕获,而在其他情况下,异常不会被捕获。

这是我的点击处理程序,其中包含代码注释,显示是否捕获了该线程上引发的异常:

private void Button_Task_Click(object sender, RoutedEventArgs e)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
throw new NotImplementedException(); //not caught
});
}

private void Button_Thread_Click(object sender, RoutedEventArgs e)
{
var thread = new System.Threading.Thread(
new System.Threading.ParameterizedThreadStart((x) =>
{
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}));
thread.Start();
}

private void Button_ThreadPool_Click(object sender, RoutedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
new System.Threading.WaitCallback((x) =>
{
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}));
}

private void Button_BWorker_Click(object sender, RoutedEventArgs e)
{
var bg = new System.ComponentModel.BackgroundWorker();
bg.DoWork += new System.ComponentModel.DoWorkEventHandler(bg_DoWork);
bg.RunWorkerAsync();
}
private void bg_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
throw new NotImplementedException(); //not caught
}

private void Button_Timer_Click(object sender, RoutedEventArgs e)
{
var timer = new System.Threading.Timer((x) =>
{
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}, null, 0, System.Threading.Timeout.Infinite);
}

这种行为对我来说似乎不一致。为什么 Timers、Thread 对象和 ThreadPool 线程会捕获异常,而 BackgroundWorkers 和 Tasks 不会?我在代码中主要使用任务、计时器和后台工作程序,因此遇到了这种不一致问题。MSDN 是否有一些文档解释 WPF 如何处理以这五种不同方式创建的线程上的未处理异常?

编辑:我使用 Action.BeginInvoke() 尝试了第六种线程创建方法。这看起来与任务类似。代码在这里:

private void Button_Action_Click(object sender, RoutedEventArgs e)
{
Action action = () =>
{
throw new NotImplementedException();
//not caught
};
action.BeginInvoke(this.DoNothing, null);
}
private void DoNothing(object arg) { }

编辑#2:我研究了引发异常的并行循环。看起来下面两个并行循环中引发的任何异常都会被捕获:

private void Button_AsParallel_Click(object sender, RoutedEventArgs e)
{
const int loops = 20;
var list = new List<int>();
for (int i = 0; i < loops; i++)
{
list.Add(i);
}

foreach (var item in list.AsParallel().Select(s => s))
{
if (item == 15)
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}
}

private void Button_ParallelFor_Click(object sender, RoutedEventArgs e)
{
const int loops = 100;
var list = new List<int>();
for (int i = 0; i < loops; i++)
{
list.Add(i);
}

System.Threading.Tasks.Parallel.For(0, loops, (int i) =>
{
if (list[i] == 90)
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
});
}

最佳答案

经过更多搜索和测试后,我将如何处理其他线程上引发的异常。对于未处理的异常,请确保在 Application.OnStartup() 顶部进行以下调用:

AppDomain.CurrentDomain.UnhandledException += 
this.CurrentDomain_UnhandledException;

为了创建线程,我更喜欢使用 System.Threading.Thread , System.Threading.ThreadPool.QueueUserWorkItem ,或System.Threading.Timer 。我找到BackgroundWorker很有用,所以我以一种更容易处理未处理异常的方式扩展了该类:

public class MyBackgroundWorker : BackgroundWorker
{
protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
throw e.Error;
else
base.OnRunWorkerCompleted(e);
}
}

我可以使用IEnumerable.AsParallelSystem.Threading.Tasks.Parallel.For对于并行循环,因为 AppDomain.CurrentDomain.UnhandledException 也会捕获它们的异常。

我会避免Tasks 。我也会避免Action<T> s,和Func<T>如果我打电话 BeginInvoke在他们。我会避免这些,因为 AppDomain.CurrentDomain.UnhandledException 没有捕获它们的异常。

关于wpf - 捕获线程、任务、计时器、ThreadPool 线程和后台工作线程上引发的 UnhandledExceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21141549/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com