我有一个任务列表,很少有任务依赖于其他任务,我想现在运行任务,如果任何任务在执行过程中失败,需要停止所有正在运行的任务并关闭应用程序。
如何使用 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++;
}