2009-08-30 11 views
6

Je souhaite avoir une approche de gestion des exceptions dans ma programmation asynchrone (beginInvoke/endInvoke) dans laquelle l'un des threads (beginInvoke) échoue, alors je veux que tous les autres threads de traitement asynchrones cessent de fonctionner. S'il vous plaît suggérer une solution ?, ci-dessous je joins mon exemple de code aussi:Gestion des exceptions de multithreading asynchrone?

public List<ThreadResultDto> SendMailAsynch(List<ThreadRequestDto> requestDto) 
{ 
    List<ThreadResultDto> resultDto = new List<ThreadResultDto>(); 
    List<IAsyncResult> asyncResults = new List<IAsyncResult>(); 

    foreach (ThreadRequestDto t in requestDto) 
    { 
     //Create a delegate. 
     DoSomeAsynchWorkDelegate del = new DoSomeAsynchWorkDelegate(DoSomeAsynchWork); 
     // Initiate the asynchronous call 
     IAsyncResult a = del.BeginInvoke(t,null, del); 
     //IAsyncResult a = del.BeginInvoke(t, null,null); 
     asyncResults.Add(a); 
    } 

    foreach (IAsyncResult ar in asyncResults) 
    { 
     // wait for each one to complete, then call EndInvoke, passing in the IAsyncResult. 
     // We cast ar.AsyncState to a DoSomeAsynchWorkDelegate, as we passed it in as the second parameter to BeginInvoke. 
     ar.AsyncWaitHandle.WaitOne(); 

     //AsyncState property of IAsyncResult is used to get the delegate that was used to call that method 
     DoSomeAsynchWorkDelegate del = (DoSomeAsynchWorkDelegate)ar.AsyncState; 

     // Call EndInvoke to get the result. Add the result to the list of items. 
     resultDto.Add(del.EndInvoke(ar)); 
    } 

    return resultDto; 
} 
+1

FYI, l'abréviation généralement acceptée de asynchrone est Async, pas Asynch :) –

Répondre

2

La meilleure façon est probablement d'utiliser un partage ManualResetEvent.

Par exemple:

class MyClass 
{ 
    private ManualResetEvent workFailedEvent = new ManualResetEvent(false); 

    public List<ThreadResultDto> SendMailAsynch(List<ThreadRequestDto> requestDto) 
    { 
     workFailedEvent.Reset(); 

     // --- The rest of your code as written in your post --- 
    } 

    private void DoAsyncWorkFirst() 
    { 
     try 
     { 
      for (int i = 0; i < 10000; i++) 
      { 
       if (workFailedEvent.WaitOne(0, true)) 
       { 
        break; 
       } 

       // -- Do some work here --- 
      } 
     } 
     catch (MyException) 
     { 
      workFailedEvent.Set(); 
     } 
    } 

    private void DoAsyncWorkSecond() 
    { 
     try 
     { 
      for (int j = 0; j < 20000; j++) 
      { 
       if (workFailedEvent.WaitOne(0, true)) 
       { 
        break; 
       } 
       // --- Do some different work here --- 
      } 
     } 
     catch (MyOtherException) 
     { 
      workFailedEvent.Set(); 
     } 
    } 
} 

La partie intéressante est ici l'appel à WaitOne (0, true). Si vous utilisez un délai de 0, le thread ne bloquera pas. Comme le ManualResetEvent est synchronisé par le système d'exploitation, cet appel de méthode particulier est un moyen pratique de vérifier un signal sans avoir à se soucier des conditions de course ou d'implémenter votre propre verrouillage.

+1

Un bool volatile ne fonctionnera-t-il pas aussi comme indicateur de terminaison? – Amnon

+0

En théorie oui. Dans certains cas, cela pourrait même être plus rapide. Mais le mot clé * volatile * a beaucoup d'effets secondaires - il change en fait la façon dont le code est généré pour chaque bloc qui accède à la variable, pas seulement la variable elle-même. Je préfère généralement les verrous et les primitives synchrones aux champs * volatils * sauf si la performance est un problème majeur. – Aaronaught

Questions connexes