タスクのリストがあり、他のタスクに依存しているタスクはほとんどありません。今すぐタスクを実行したいのですが、実行中にいずれかのタスクが失敗した場合は、実行中のすべてのタスクを停止してアプリケーションを閉じる必要があります。
TPLでこれを行うにはどうすればよいですか? 実行中のタスクを停止するには? 以下のコードを最適化する必要があります。
詳細要件 ・ ログオン画面をタスクとして起動する。o ログオンが成功した場合にのみ、他のすべてのタスクを並行して実行します。o ログオン失敗またはキャンセルの場合はアプリケーションを終了 - いずれかのタスクが失敗した場合はアプリケーションを終了します
var done = new List<TaskDetails>();
var executing = new List<TaskDetails>();
var unblocked = new List<TaskDetails>();
var blocked = new List<TaskDetails>();
foreach (var startupTest in startupTests) {
if (startupTest.DependsOn == null) {
unblocked.Add(startupTest);
} else {
blocked.Add(startupTest);
}
}
IDictionary<int, TaskDetails> tasksByID = new Dictionary<int, TaskDetails>();
var tasksTPL = new Task<object>[startupTests.Count];
var taskCount = 0;
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
while (done.Count < startupTests.Count) {
while (executing.Count < config.MaximumConcurrency && unblocked.Count > 0) {
TaskDetails nextTask = unblocked[0];
lock (syncLock) {
unblocked.Remove(nextTask);
executing.Add(nextTask);
}
// Execute
try {
var method = GetMethod(
nextTask.AssemblyName, nextTask.ClassName, nextTask.MethodName
);
if (method == null) {
throw new Exception("Method" + nextTask.MethodName + " not available.");
}
tasksTPL[taskCount] =
Task<object>.Factory.StartNew(() => method.Invoke(null, null),
cancellationToken);
tasksByID.Add(tasksTPL[taskCount].Id, nextTask);
tasksTPL[taskCount].ContinueWith(tsk => {
lock (syncLock) {
done.Add(tasksByID[tsk.Id]);
executing.Remove(tasksByID[tsk.Id]);
}
if (tsk.Exception != null) {
TraceAlways(
"Caught Exception while running startuptest: " +
tsk.Exception
);
}
});
taskCount++;
} catch (TargetInvocationException e) {
TraceAlways(
"Failed running " + nextTask.MethodName + " method." + e.Message);
}
}
Task.WaitAny(tasksTPL.Where(task => task != null).ToArray());
var toRemove = new List<TaskDetails>();
lock (syncLock) {
List<string> doneTaskName =
done.Select(TaskDetails => TaskDetails.Name).ToList();
foreach (var task in blocked) {
bool isBlocked = task.DependsOn.Any(dep => !doneTaskName.Contains(dep));
if (!isBlocked) {
toRemove.Add(task);
unblocked.Add(task);
}
}
foreach (var TaskDetails in toRemove) {
blocked.Remove(TaskDetails);
}
}
if (executing.Count == 0 && unblocked.Count == 0 && blocked.Count > 0) {
throw new Exception("Cyclic Dependency");
}
}
taskCount = 0;
foreach (var task in tasksTPL) {
if (
(task.Status != TaskStatus.Faulted) &&
(task.Result is bool) &&
(!(bool)task.Result)
) {
TraceAlways("Startup Test" + startupTests[taskCount].MethodName + " failed.");
if (startupTests[taskCount].ShowNotification) {
cancellationTokenSource.Cancel();
MessageBox.Show(
"An error has accoured. See log for more details.", "Startup Error"
);
}
Environment.Exit(0);
break;
}
taskCount++;
}