2009-08-30 23 views
6

私は非同期プログラミング(beginInvoke/endInvoke)でスレッド(beginInvoke)のいずれかが失敗した場合、他のすべての非同期処理スレッドが動作を停止するようにするアプローチを取りたいと思います。私はまた私のサンプルコードを添付しています下の?いくつかのソリューションを提案してください:非同期マルチスレッド例外処理?

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、非同期の一般的に受け入れられている省略形はAsyncではなく、Asynchです。 –

答えて

2

最良の方法は、共有ManualResetEventを使用することが考えられます。例えば

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(); 
     } 
    } 
} 

ここで興味深い部分はWAITONE(0、真)の呼び出しです。タイムアウトが0の場合、スレッドはブロックされません。 ManualResetEventはOSによって同期されているので、この特定のメソッド呼び出しは、競合状態を心配することなく、または独自のロックを実装することなく、信号をチェックする便利な方法です。

+1

揮発性ブールも終了フラグとして機能しませんか? – Amnon

+0

理論上はい。場合によっては、さらに高速になる場合もあります。しかし、* volatile *キーワードには多くの副作用があります。実際には変数自体に限らず、変数にアクセスするブロックごとにコードが生成される方法が実際に変更されています。パフォーマンスが大きな問題でない限り、私は一般的にロックフィールドやシンクロプリミティブをvolatileフィールドに優先します。 – Aaronaught