2009-08-30 16 views
6

Quiero tener un enfoque de manejo de excepciones en mi programación asíncrona (beginInvoke/endInvoke) donde si alguno de los hilos (beginInvoke) falla, entonces quiero que todos los demás hilos de procesamiento asincrónicos dejen de funcionar. Para sugerir alguna solución ?, a continuación os adjunto mi código de ejemplo también:Manejo de excepciones de subprocesamiento asíncrono?

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, la abreviatura generalmente aceptada de asincrónico es Async, no Asynch :) –

Respuesta

2

La mejor manera es probablemente usar un compartida ManualResetEvent.

Por ejemplo:

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 parte interesante aquí es la llamada a WaitOne (0, true). Si usa un tiempo de espera de 0, entonces el hilo no se bloqueará. Como el ManualResetEvent está sincronizado por el sistema operativo, esta llamada a un método particular es una forma conveniente de buscar una señal sin tener que preocuparse por las condiciones de carrera o implementar su propio bloqueo.

+1

¿No funcionará un bool volátil como una bandera de terminación? – Amnon

+0

En teoría sí. En algunos casos, incluso podría ser más rápido. Pero la palabra clave * volátil * tiene muchos efectos secundarios: de hecho cambia la forma en que se genera el código para cada bloque que accede a la variable, no solo la variable misma. Generalmente prefiero bloqueos y primitivas sincronizadas a campos * volátiles a menos que el rendimiento sea un problema importante. – Aaronaught