lundi 18 octobre 2010

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

Comme précisé dans l'article "Threading en C# - synchronisation et méthodes de threading", voici un exemple d'implémentation event-based asynchronous pattern (utilisant le ThreadPool) et supportant la réantance.
L'article précédent "Threading en C# - exemple event-based asynchronous pattern (sans réentrance)" implémentait le même pattern mais sans réentrance

Note: les exemples sont développés avec Snippet Compiler.

L'implémentation 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).
Tout comme l'exemple précédent, l'implémentation est faite autour d'une simple classe (au lieu d'un composant).

Code de test
public class MyClass
{
    public static void RunSnippet()
    {
        List<string> sourceList = new List<string>();
        sourceList.Add( "Test 1" );
        sourceList.Add( "This Stuff text" );
        sourceList.Add( "Some other tests" );
        sourceList.Add( "dodo" );


        // Test of the Re-entrant EventBased Asynchronous pattern
        // The unique taskId identifier will be the string reference himself
        TestClass myTest = new TestClass();
        myTest.ComputeTextCompleted += ComputeTextCompletedCallback;
        foreach( String str in sourceList ) {                        
            myTest.ComputeTextAsync( str, str );  // appels multiples :-)
WL( String.Format( "ComputeTextAsync called for \"{0}\"", str ));
        }

        // Cancel while working
        WL( String.Format( "Send cancellation for {0}", sourceList[2] ) );
        myTest.CancelTextAsync( sourceList[2] );
    }
    
    public static void ComputeTextCompletedCallback( object sender, ComputeTextCompletedEventArgs e ) {
        // The unique identifier e.TaskID is the reference to the source text
        if( e.Canceled ) {
            WL( "" );
            WL( String.Format( "ComputeTextCompletedCallback() received cancellation for \"{0}\" :-( ", (string)(e.TaskId) ));
            WL( "" );            
        }
        else {
            WL( "" );
            WL( String.Format( "ComputeTextCompletedCallback() received computed text for \"{0}\"", (string)(e.TaskId) ));
            WL( e.ComputedText );
            WL( "" );
        }
    }
    ...
}

Résultat du code de test
ComputeTextAsync called for "Test 1"
ComputeTextAsync called for "This Stuff text"
ComputeTextAsync called for "Some other tests"
ComputeTextAsync called for "dodo"
Send cancellation for Some other tests
Press any key to continue...  notez que le code appelant s'interrompt ici
ComputeTextCompletedCallback() received cancellation for "Some other tests" :-(

ComputeTextCompletedCallback() received computed text for "This Stuff text"
 *$+-*/This Stuff text*$+-*/

ComputeTextCompletedCallback() received computed text for "Test 1"
 *$+-*/Test 1*$+-*/

ComputeTextCompletedCallback() received computed text for "dodo"
 *$+-*/dodo*$+-*/

Code Source
Fichier: Threading_EventBasedAsynchronousPattern_Reentrancy.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.
Le code n'est pas publié directement dans ce post car il est assez long. Il est par contre accessible via le lien vers le fichier Threading_EventBasedAsynchronousPattern_Reentrancy.cs.

A toute fin utile, le précédent exemple "Threading en C# - exemple event-based asynchronous pattern (sans réentrance)" était accompagné d'un Diagramme de séquence détaillant le fonctionnement du pattern. Le fonctionnement reste identique dans les deux cas (avec et sans réentrance).

Aucun commentaire: