4

重複: ThreadPool.QueueUserWorkItem から例外をキャッチする方法は?


複数のデータベースやその他のオフライン リソースを呼び出す多数の独立したリモート呼び出しのために、.Net ThreadPool で複数のデリゲートをキューに入れています。これらの呼び出しを ThreadPool のキューに入れることで、それらを同時に実行し、全体的な待ち時間を最小限に抑えることができます。

private void CompleteAndQueuePayLoads(IEnumerable<UsagePayload> payLoads)
{
    List<WaitHandle> waitHndls = new List<WaitHandle>();
    foreach (UsagePayload uPyLd in payLoads)
    {
        ManualResetEvent txEvnt = new ManualResetEvent(false);
        UsagePayload uPyLd1 = uPyLd ;
        ThreadPool.QueueUserWorkItem(
            delegate
                {
                    if (!uPyLd1 .IsComplete)
                        // IEEDAL.GetPayloadReadings is long running DB call
                        try { IEEDAL.GetPayloadReadings(uPyLd1 ); }
                        catch (IEEAccessException iX)
                        {
                            log.Write(log.Level.Error,
                                  "IEEWSDAL.CompleteAndQueuePayLoads " + 
                                   " Delegate Failed " +
                                  iX.Message, iX);
                            txEvnt.Set();
                            throw;  // this causes parent thread to crash!
                            // was going to try Thread.Abort next ...
                            // Thread.CurrentThread.Abort();
                        }
                    UsageCache.PersistPayload(uPyLd1 );
                    SavePayLoadToProcessQueueFolder(uPyLd1 );
                    txEvnt.Set();
                });
        waitHndls.Add(txEvnt);
    }
    util.WaitAll(waitHndls.ToArray()); //To waitone on > 64 waithandles
}

ただし、バッチ全体をトランザクションで処理する必要があります。つまり、すべての子スレッドが成功した場合にのみ、親スレッドの出力を続行できるようにする必要があります。失敗したときにカスタム例外をスローするように子スレッドをコーディングしましたが、これらの例外は親スレッドで「キャッチ」できないため、これにより親スレッドがクラッシュすることがわかりました...

これが発生したときに CLR によって UnHandledExceptionEvent がスローされることについて読みましたが、これらの子スレッドがキューに入れられて生成されるメソッドでこの例外を「処理」して、子の成功に基づいてすぐに下流の処理を制御する必要があります。 threeads...どうすればいいですか?

4

3 に答える 3

3

スレッドが失敗した場合、CompleteAndQueuePayLoads 関数のローカル変数内で少なくとも 1 つの失敗が発生したことをマークし、後で調べるために例外/失敗変数を追加できます。

于 2009-03-20T22:58:02.567 に答える
2

私は現在のプロジェクトでこれを頻繁に行っています。私がとったアプローチは、デリゲートを受け取り、それを自分のキューに追加し、それらを実行して最後に同期を処理するなど、独自のスケジューラを作成することでした。

この場合に使用した "トリック" は、スレッド プールでデリゲートを直接呼び出すのではなく、デリゲートをラップして例外をより適切に処理するスケジューラのメソッドを呼び出すことです。このようにして、実際の内部メソッド呼び出しは常に (私にとって) 適切な方法で処理されます。

例外が発生すると、私のスケジューラーは通知を受け、将来のタスクのスケジューリングを停止します (これは素晴らしいボーナスです)。また、1 つの例外があったことを発信者に伝えるようにします。

于 2009-03-21T01:04:29.470 に答える
1

3.5 の Parallel ライブラリ拡張機能を調べることができます。コード ブロックで Parallel.Invoke を使用して、実行しようとしている処理を正確に行うことができます。

于 2009-10-29T05:31:55.537 に答える