vendredi 8 octobre 2010

Threading en C# - exemple event-based asynchronous pattern (sans réentrance)

Comme précisé dans l'article "Theading en C# - synchronisation et méthodes de threading", voici un exemple d'implémentation event-based asynchronous pattern (utilisant le ThreadPool) sans support de la réentrance.
Note: les exemples sont développés avec Snippet Compiler.

L'implementation du pattern  "Event-based asynchronous pattern" n'est pas des plus simple et doit être scrupuleusement suivit.
Cet exemple est issue d'un article MSDN supportant la réentrance et implémentant le pattern pour un composant (ce qui le cas d'utilisation le plus approprié de ce pattern).
Pour le besoin de l'exemple et du test, j'ai abandonné  l'implémentation de type Composant pour favoriser l'implémentation du pattern dans la classe de test  TestClass.

Code de test
public class MyClass
{
 public static void RunSnippet()
 {
  // Test of the NON recurrent EvebntBased Asynchronous pattern
  //    (cannot be called several times while processing async event)
  TestClass myTest = new TestClass();
  myTest.ComputeTextCompleted += ComputeTextCompletedCallback;
  myTest.ComputeTextAsync( "This Stuff text" );
  
  try {
   myTest.ComputeTextAsync( "This test will fire exception" );   
  }
  catch(Exception e ){
   WL( "Cannot recall non recurrent Async while working!" );
   WL( String.Format("Exception while calling ComputeTextAsync(). {0} with message \"{1}\"", e.GetType().Name, e.Message ));
  }
  
  // Wait while async call is busy
  while( myTest.IsBusy )
   Thread.Sleep( 10 );
  myTest.ComputeTextAsync( "Second test" );

  // Cancel while working
  while( myTest.IsBusy )
   Thread.Sleep( 10 );
  myTest.ComputeTextAsync( "Third test" );
  Thread.Sleep( 500 );
  myTest.CancelAsync();
  
  // Wait to exit
  while( myTest.IsBusy )
   Thread.Sleep( 10 );  
 }
        ...
}

Résultat du code de test
Cannot recall non recurrent Async while working!
Exception while calling ComputeTextAsync(). ArgumentException with message "Task
 ID parameter must be unique
Nom du paramètre : taskId"

ComputeTextCompletedCallback() received computed text :-)
---This Stuff text---


ComputeTextCompletedCallback() received computed text :-)
---Second test---

Press any key to continue...
ComputeTextCompletedCallback() received cancellation :-(

Code Source
Fichier: Threading_EventBasedAsynchronousPattern.cs

Si le code de test démontre le bon fonctionnement de l'ensemble, c'est surtout le code implémentant le pattern qui est le plus intéressant.
Mais ce code n'est pas publié directement dans ce pot car il est assez long. Il est par contre accessible via le lien vers le fichier Threading_EventBasedAsynchronousPattern.cs.

Dans ce code, le traitement est pris en charge par la worker méthode ComputeTextWorker.
Afin de faciliter la compréhension de l'ensemble, le graphique suivant reprend un descriptif des différents appels (avec quelques annotations).

Classe MyClass:
Classe de test (l'appelant) du snippet permettant de tester l'exactitude de l'implémentation du pattern.
Cette classe est utilisée pour faire l'appel à ComputeTextAsync et attend le résultat fournit par l'évènement ComputeTextCompleted.

Classe TestClass:
Implémente le pattern "Event Based Asynchronous Pattern".
C'est le fonctionnement de cette classe qui est testée.

Cliquer pour agrandir
1*: Utilisation du OnCompletedDelegate via une opération asynchrone pour que l'exécution se fasse sur le thread approprié.
2*: La méthode OnComputeTextCompleted sert a déclencher l'évènement ComputeTextCompleted.
3*: Appel la méthode ComputeTextCompleteCallback de MyClass.

Aucun commentaire: