mardi 28 septembre 2010

Threading en C# - exemple BackgroundWorker

Comme précisé dans l'article "Theading en C# - synchronisation et méthodes de threading", voici deux exemples d'utilisation des background worker.
Note: les exemples sont développés avec Snippet Compiler.

Ce premier exemple est le plus simple... consiste juste en la création d'un Background Worker.
Fichier: Threading_BackgoundWorker.cs.

public class MyClass
{
 static BackgroundWorker bw;
  
 public static void RunSnippet()
 {
  bw = new BackgroundWorker();
  bw.WorkerReportsProgress = true;
  
  bw.DoWork += bw_DoWork;
  bw.RunWorkerAsync( "Message to display"  );
 }
 
 static void bw_DoWork( object sender, DoWorkEventArgs e ){
  Console.WriteLine( e.Argument );
 }   
 ...
}

Ce deuxième exemple met en place le processus de reporting, cancellation et événement complete.
Ce deuxième exemple documente également une méthode (proposé sur MSDN) pour simuler le Join Pattern pour un BackgroundWorker.
En effet, un BackgroundWorker travaille en tâche de fond et le thread principal n'est pas censé attendre la fin de son exécution. Une autre solution serait de partager un AutoResetEvent.
Fichier: Threading_BackgoundWorker_Progress.cs.

using System;
using System.Collections.Generic;
using System.Threading;
using System.ComponentModel;

public class MyClass
{
 static BackgroundWorker bw;
 public static void RunSnippet()
 {
  bw = new BackgroundWorker();
  bw.WorkerReportsProgress = true;
  bw.WorkerSupportsCancellation = true;
  bw.DoWork += bw_DoWork;
  bw.ProgressChanged += bw_ProgressChanged;
  bw.RunWorkerCompleted += bw_RunWorkerCompleted;
  
  bw.RunWorkerAsync ("Running the worker" );
    
  /* === Wait the BackgroundWorker ====
  The Join pattern does not exits for background worker.
  background are supposed to offer background processing while keeping the UI responsive.
  
  Anyway, if you need to wait for a worker to finish (eg: downloaded), here a solution proposed on MSDN. 
     http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.isbusy.aspx
   
  while (bw.IsBusy)
     {
         // Perform some UI progression
   //     progressBar1.Increment(1);
   
         // Keep WinForm UI messages moving, so the form remains 
         // responsive during the asynchronous operation.
         Application.DoEvents();
     } 
  */
 
  WL( "5 Seconds to press ENTER... this will send a Cancel to the worker");
  RL();
  if( bw.IsBusy )
   bw.CancelAsync();
  WL( "End of program" );
  
 }
 
 public static void bw_DoWork( object sender, DoWorkEventArgs e ){
  for( int i = 0; i <= 100; i+=20){
   if( bw.CancellationPending ){
    e.Cancel = true;
    return;
   }
   bw.ReportProgress(i);
   Thread.Sleep( 1000 );
  }
  e.Result = 123; // value for RunWorkerCompleted event
 }
 
 public static void bw_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
  if( e.Cancelled )
   WL( "Worker has been cancelled!");
  else 
   if (e.Error != null)
    WL( String.Format("Worker got an exception {0} with message {1}", e.GetType().ToString(), e.Error.ToString()) );
   else
    WL( String.Format("Worker completed with value {0}", e.Result ));
 }
 
 public static void bw_ProgressChanged( object sender, ProgressChangedEventArgs e ){
  WL( String.Format( "Reached {0}% value", e.ProgressPercentage) );
 }
        ...
 
}

Aucun commentaire: