BackgroundWorker dies unexpectedly

2019-08-12 14:48发布

I have the following code:

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);
   }
 }
}

The backgroundworker thread died unexpectedly without any exception being thrown. I did not encounter this problem during development and it seems to be hard to reproduce. I suspected that maybe a cross thread exception was occurring when I am doing work in the scheduler_DoWork. I have tried to explicitly update the UI without checking if InvokeRequired and the thread continues to run without problems in a release build. How can this be? (Cross thread exception should occur) How can I determine what causes the thread to die? Any suggestions on how to figure out what is going wrong or how to debug this issue will be appreciated?

4条回答
一纸荒年 Trace。
2楼-- · 2019-08-12 15:30

You can do several things to increase the possibility of catching the exception:

  • Enable Managed Debugging Assistants for all exceptions in VS. To do that, go to Debug menu -> Exceptions..., and put a check mark next to "Managed Debugging Assistants" to enable all exceptions to be caught using debugger. Also, depending on the code you are executing, expand the CLR Exceptions node and select nodes of interest ("System" node, for example, will catch all exceptions from the System namespace in the debugger).

  • Obviously, put a try/catch block around your code, with some logging. You can also do something like this, if you are in real trouble:

  try
  {
      // do stuff
  }
  catch (Exception ex)
  {

#if DEBUG
      // break only in DEBUG builds
      System.Diagnostics.Debugger.Break();
#endif

      // log the exception and throw
      throw;
  }
  • Put a try/catch with logging around your Application.Run(...) code in the Main() method. Exceptions do propagate up there sometimes, and this can catch them (even if not coming from this specific part of your code).

  • Add an Application.ThreadException event handler in your Main() method, before calling Application.Run, like this:

Application.ThreadException +=
   new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

查看更多
女痞
3楼-- · 2019-08-12 15:34

The RunWorkerCompleted event might not be fired on the UI Thread. If it is not, then the thread will end and your scheduler object will be garbage collected, which will make it seem like it just quit with no error. See this post for more details. Here and here are SO posts about this.

查看更多
男人必须洒脱
4楼-- · 2019-08-12 15:39

Your sample doesn't show enough code to determine what's going on but:

  • Maybe an exception is being thrown from ThreadSafeShowError? Why are you trying to show an error from the worker thread anyway - the conventional thing to do is to show e.Error if not null in the RunWorkerCompleted event handler.

To debug the issue try putting the following around all the code in your DoWork handler:

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
}
查看更多
Evening l夕情丶
5楼-- · 2019-08-12 15:43

In Mainform, you never call scheduler.RunWorkerAsync, so your BackgroundWorker does not start at all.

查看更多
登录 后发表回答