BackgroundWorker意外死亡

时间:2009-11-05 18:51:17

标签: c# backgroundworker

我有以下代码:

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和线程是否继续在发布版本中运行没有问题。怎么会这样? (应该发生跨线程异常)如何确定导致线程死亡的原因?有关如何找出问题或如何调试此问题的任何建议将不胜感激?

4 个答案:

答案 0 :(得分:2)

可能不会在UI线程上触发RunWorkerCompleted事件。如果不是,那么线程将结束并且您的调度程序对象将被垃圾收集,这将使它看起来好像只是退出而没有错误。有关详细信息,请参阅this帖子。 Herehere是关于此的帖子。

答案 1 :(得分:1)

您的示例没有显示足够的代码来确定发生了什么,但是:

  • 可能是ThreadSafeShowError抛出异常?为什么要尝试显示工作线程中的错误 - 传统的做法是在RunWorkerCompleted事件处理程序中显示e.Error(如果不为null)。

要调试此问题,请尝试将以下代码放在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根本无法启动。