我有以下代码:
public Mainform()
{
...
// scheduler
scheduler.DoWork += new System.ComponentModel.DoWorkEventHandler(scheduler_DoWork);
scheduler.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(scheduler_RunWorkerCompleted);
scheduler.WorkerReportsProgress = false;
scheduler.WorkerSupportsCancellation = true;
...
...
scheduler_DoWork(this, null);
scheduler.RunWorkerAsync(1000);
...
}
void scheduler_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
scheduler_Enabled = false;
CustomExceptionHandler eh = new CustomExceptionHandler();
eh.HandleUnhandledException(e.Error, "scheduler");
}
if(scheduler_Enabled)
{
scheduler.RunWorkerAsync(1000);
}
}
void scheduler_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
try
{
...do some stuff
}
catch(MyException ex)
{
ThreadSafeShowError();
}
finally
{}
...do more stuff
}
finally
{
if (e != null && e.Argument != null)
{
Thread.Sleep((int)e.Argument);
}
}
}
backgroundworker线程意外死亡,没有任何异常被抛出。我在开发过程中没有遇到这个问题,似乎很难再现。我怀疑当我在scheduler_DoWork中工作时可能发生了跨线程异常。我试图显式更新UI而不检查InvokeRequired和线程是否继续在发布版本中运行没有问题。怎么会这样? (应该发生跨线程异常)如何确定导致线程死亡的原因?有关如何找出问题或如何调试此问题的任何建议将不胜感激?
答案 0 :(得分:2)
可能不会在UI线程上触发RunWorkerCompleted事件。如果不是,那么线程将结束并且您的调度程序对象将被垃圾收集,这将使它看起来好像只是退出而没有错误。有关详细信息,请参阅this帖子。 Here和here是关于此的帖子。
答案 1 :(得分:1)
您的示例没有显示足够的代码来确定发生了什么,但是:
要调试此问题,请尝试将以下代码放在DoWork处理程序中的所有代码中:
try
{
// do work
// log a trace statement here
}
catch(Exception ex)
{
// log exception, e.g. with System.Diagnostics.Debug.Write
throw;
}
finally
{
// log a trace statement here
}
答案 2 :(得分:1)
您可以做几件事来增加捕获异常的可能性:
为VS中的所有例外启用托管调试助手。为此,请转到“调试”菜单 - >异常......,并在“托管调试助手”旁边放置一个复选标记,以便使用调试器捕获所有异常。此外,根据您正在执行的代码,展开CLR Exceptions节点并选择感兴趣的节点(例如,“System”节点将捕获调试器中System
命名空间中的所有异常。)
显然,在代码周围放置一个try / catch块,并进行一些日志记录。如果遇到麻烦,你也可以这样做:
try
{
// do stuff
}
catch (Exception ex)
{
#if DEBUG
// break only in DEBUG builds
System.Diagnostics.Debugger.Break();
#endif
// log the exception and throw
throw;
}
在Application.Run(...)
方法中使用try / catch记录Main()
代码。有时异常会在那里传播,这可以捕获它们(即使不是来自代码的这个特定部分)。
在调用Application.ThreadException
之前,在Main()
方法中添加Application.Run
事件处理程序,如下所示:
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
答案 3 :(得分:0)
在Mainform
中,您永远不会调用scheduler.RunWorkerAsync
,因此您的BackgroundWorker根本无法启动。