5

I crear hilo con BackgroundWorker, y en el bucle I comprobar cada vez si CancellationPending es verdad o no, como este:¿Qué tan cerca está el subproceso BackgroundWorker cuando la aplicación está desactivada?

public MainPage() 
    { 
     InitializeComponent(); 

     bw = new BackgroundWorker(); 
     bw.WorkerReportsProgress = true; 
     bw.WorkerSupportsCancellation = true; 
     bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
     bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
     bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
    } 

    private void ButtonStart_Click(object sender, RoutedEventArgs e) 
    { 
     if (bw.IsBusy != true) 
     { 
      bw.RunWorkerAsync(); 
     } 
    } 

    private void ButtonCancel_Click(object sender, RoutedEventArgs e) 
    { 
     if (bw.WorkerSupportsCancellation) 
     { 
      bw.CancelAsync(); 
     } 
    } 

    private void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = sender as BackgroundWorker; 

     for (int i = 1; i <= 100; i++) 
     { 
      Debug.WriteLine("The tread is working"); 
      if (worker.CancellationPending) 
      { 
       e.Cancel = true; 
       bw.CancelAsync(); 
       break; 
      } 
      else 
      { 

       System.Threading.Thread.Sleep(500); 
       worker.ReportProgress(i); 
      } 
     } 
    } 

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Cancelled) 
     { 
      tbProgress.Text = "Canceled"; 
     } 
     else if (e.Error != null) 
     { 
      tbProgress.Text = "Error: " + e.Error.Message; 
     } 
     else 
     { 
      tbProgress.Text = "Done"; 
     } 
    } 

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     tbProgress.Text = e.ProgressPercentage.ToString() + "%"; 
    } 

Cuando se desactiva la aplicación, el hilo no se cerró, se aborta y la excepción ocurre ¿Qué tan cerca está el hilo con BackgroundWorker cuando la aplicación está desactivada?

+0

¿Lo has probado? ¿Hace lo que necesitas? –

+0

@ liho1ey Sí, lo probé y cuando la aplicación se desactivó recibí una excepción. Escribo estos códigos en la página xaml.cs, no en el nivel de aplicación. –

+0

bien, pero ¿está llamando 'CancelAsync()'? –

Respuesta

5

¿Ha configurado el BackgroundWorker para ser cancelable?

var bg= new BackgroundWorker(); 
bg.WorkerSupportsCancellation = true; 

De la documentación:

Establecer la propiedad WorkerSupportsCancellation en true si desea que el BackgroundWorker para apoyar la cancelación. Cuando esta propiedad es verdadera, puede llamar al método CancelAsync para interrumpir una operación en segundo plano.

también su código parece estar mal, debe llamar a la CancelAsync() fuera de su código de hilo, esto va a establecer el indicador CancellationPending que se puede utilizar para salir del bucle.

Aunque no estoy 100% seguro ya que no sé de dónde viene la variable bw. `

+0

Edito mi código. Por favor, mira aquí está mi código completo. Y sí configuro WorkerSupportsCancellation verdadero/ –

+0

como dije, elimine la línea 'bw.CancelAsync()' de su método do_Work. También sería útil si publicas qué excepción obtienes – thumbmunkeys

+0

¿dónde? Y cuando habilité thombstone en la depuración de las propiedades del proyecto recibo una excepción: una excepción de primera oportunidad del tipo 'System.Threading.ThreadAbortException' ocurrió en mscorlib.dll Se produjo una primera excepción de tipo 'System.Threading.ThreadAbortException' en el sistema. dll –

2

Debe verificar el indicador de cancelación de cancelación en su método de trabajador y salir con gracia si se establece el indicador.
¿Cuál es la condición para la cancelación del trabajo? Botón de cancelar Haga clic en? Luego debe poner allí la llamada a CancelAsync (...). Establecerá el indicador de cancelación de cancelación que ya está registrando en su código, evitando la necesidad de algo como un objeto ResetEvent.

+0

@ 9S6 No la condición para CancelationPending es el estado de la aplicación desactivada. Quiero que BW cierre el threth cuando la aplicación esté thombstoned y continue thread cuando la aplicación se active. –

+0

¿Dónde debo verificar CancelationPending? –

+0

Debería llamar a CancelAysnc (...) cuando su aplicación esté desactivada y volver a iniciar BackgroundWorker cuando la aplicación esté activada. Llamar a CancelAsync (...) configurará el indicador CancellationPending. Ya está verificando ese indicador en su método de trabajo: simplemente elimine la llamada a CancelarAsinc (...) desde allí. – A9S6

10

Cuando una aplicación está desactivada, cada hilo que no sea el de la interfaz de usuario principal lanzará una excepción ThreadAbortException tan pronto como se active. Esto parece ser "por diseño" como una forma de obligar a las aplicaciones a detener rápidamente lo que están haciendo. Los hilos pueden atrapar la ThreadAbortException y concluir lo que están haciendo, pero tenga en cuenta que la ThreadAbortException se elevará automáticamente de nuevo al final del bloque catch. Cualquier código en un bloque finally también se ejecutará.

Para su problema específico, no hay ninguna razón para intentar cancelar el BackgroundWorker cuando la aplicación se desactiva debido a que ThreadAbortException ocurrirá y se detendrá efectivamente el trabajador de fondo. Si desea hacer algo para limpiar cuando ocurre esto, atrapa la excepción ThreadAbortException en bw_DoWork, haga lo que necesita hacer y luego déjelo morir.

Para que comience nuevamente después de la activación, debe reiniciar el trabajador en segundo plano, tal como lo hizo la primera vez que ejecutó la aplicación.

+0

Ok, gracias. (15 caracteres) –

+0

Esta es la mejor respuesta – Calanus

1

Quiero agregar un punto de aclaración a las respuestas anteriores, basado en mis propias observaciones. Los subprocesos de fondo sobreviven a la desactivación/activación cuando se conserva la instancia.

tuve código que se veía así:

private void Application_Activated(object sender, ActivatedEventArgs e) 
{ 
    if (e.IsApplicationInstancePreserved) 
    { 
     Log.write("Activating, instance preserved"); 
     // restart long-running network requests 
     startBackground(); 
    } 
    else // start over again 
    { 
     AppSettings.init(); 
     Log.write("Activating, rehydrating"); 
     startBackground(); 
    } 
} 

También registra el código hash del objeto BackgroundWorker cuando se ejecuta.Lo que vi fue que cada vez que recibía un mensaje de "Activación, instancia conservada", recibí un BackgroundWorker adicional ejecutándose.

En base a esto, ¿parece más probable decir que los hilos se abortan en el tumulto, no en la desactivación?

Cuestiones relacionadas