例外をスローする次のコードがあります。
ThreadPool.QueueUserWorkItem(state => action());
アクションが例外をスローすると、プログラムがクラッシュします。この状況を処理するためのベスト プラクティスは何ですか?
例外をスローする次のコードがあります。
ThreadPool.QueueUserWorkItem(state => action());
アクションが例外をスローすると、プログラムがクラッシュします。この状況を処理するためのベスト プラクティスは何ですか?
次のように try/catch を追加できます。
ThreadPool.QueueUserWorkItem(state =>
{
try
{
action();
}
catch (Exception ex)
{
OnException(ex);
}
});
のソース コードにアクセスできる場合はaction、そのメソッドに try/catch ブロックを挿入します。それ以外の場合は、呼び出しをtry/catch ブロックにtryActionラップする新しいメソッドを作成します。action
.Net 4.0 を使用している場合は、 Taskクラスを調べてみる価値があるかもしれません。
元のコードと同等ですが、タスクを使用すると、次のようになります
Task.Factory.StartNew(state => action(), state);
例外に対処するために、StartNew によって返される Task に継続を追加できます。次のようになります。
var task = Task.Factory.StartNew(state => action(), state);
task.ContinueWith(t =>
{
var exception = t.Exception.InnerException;
// handle the exception here
// (note that we access InnerException, because tasks always wrap
// exceptions in an AggregateException)
},
TaskContinuationOptions.OnlyOnFaulted);
もう一方のスレッドで、(「キューイング」しているメソッドで、try catch 句を追加します....次に、キャッチで、キャッチされた例外を共有 Exception 変数に配置します (メインスレッドに表示されます)。
次に、メインスレッドで、キューに入れられたすべてのアイテムが終了したら(これには待機ハンドル配列を使用します)、その共有例外に例外が設定されているスレッドがあるかどうかを確認します...そうであれば、それを再スローするか、適切に処理します...
これを使用した最近のプロジェクトのサンプルコードを次に示します...
HasExceptionは共有ブール値です...
private void CompleteAndQueuePayLoads(
IEnumerable<UsagePayload> payLoads, string processId)
{
List<WaitHandle> waitHndls = new List<WaitHandle>();
int defaultMaxwrkrThreads, defaultmaxIOThreads;
ThreadPool.GetMaxThreads(out defaultMaxwrkrThreads,
out defaultmaxIOThreads);
ThreadPool.SetMaxThreads(
MDMImportConfig.MAXCONCURRENTIEEUSAGEREQUESTS,
defaultmaxIOThreads);
int qryNo = 0;
foreach (UsagePayload uPL in payLoads)
{
ManualResetEvent txEvnt = new ManualResetEvent(false);
UsagePayload uPL1 = uPL;
int qryNo1 = ++qryNo;
ThreadPool.QueueUserWorkItem(
delegate
{
try
{
Thread.CurrentThread.Name = processId +
"." + qryNo1;
if (!HasException && !uPL1.IsComplete)
IEEDAL.GetPayloadReadings(uPL1,
processId, qryNo1);
if (!HasException)
UsageCache.PersistPayload(uPL1);
if (!HasException)
SavePayLoadToProcessQueueFolder(
uPL1, processId, qryNo1);
}
catch (MeterUsageImportException iX)
{
log.Write(log.Level.Error,
"Delegate failed " iX.Message, iX);
lock (locker)
{
HasException = true;
X = iX;
foreach (ManualResetEvent
txEvt in waitHndls)
txEvt.Set();
}
}
finally { lock(locker) txEvnt.Set(); }
});
waitHndls.Add(txEvnt);
}
util.WaitAll(waitHndls.ToArray());
ThreadPool.SetMaxThreads(defaultMaxwrkrThreads,
defaultmaxIOThreads);
lock (locker) if (X != null) throw X;
}
私が通常行うことは、大きな try ... catch ブロックを action() メソッド内に作成し、例外をプライベート変数として保存してから、メインスレッド内で処理することです