Ich versuche, eine Kill
Option für einen Fall zu aktivieren, der asynchron vom aufrufenden Thread als Process
ausgeführt wird. Mein Beispiel sieht wie @ svicks Antwort here aus. Ich versuche die Empfehlung von @svick in diesem post zu implementieren. Aber wenn ich in der Benutzeroberfläche auf Kill
klicke, scheint es nichts zu tun (d. H. Der Prozess läuft einfach wie gewöhnlich zum Abschluss).Einen Prozess mit CancellationToken stoppen
Gemäß @ TimCopenhavers Antwort wird dies erwartet. Aber wenn ich das kommentierte, tut es immer noch nichts, dieses Mal, weil das CancellationTokenSource
Objekt cts
null ist, was unerwartet ist, da ich es in der Dispatch
Methode der Klasse instanziiere, bevor ich versuche, es zu töten. Hier ist mein Code-Schnipsel:
UI
Klasse:
private void OnKillCase(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Args caseArgs = CaseAPI.GetCaseArguments(case);
CaseDispatcher dispatcher = CaseAPI.GetCaseDispatcher(case);
dispatcher.Kill();
CaseAPI.Dispose(caseArgs);
}
}
CaseDispatcher
Klasse:
private Task<bool> task;
private CancellationTokenSource cts;
public override bool IsRunning
{
get { return task != null && task.Status == TaskStatus.Running; }
}
public override void Kill()
{
//if (!IsRunning)
//{
// return;
//}
if (cts != null)
{
cts.Cancel();
}
}
public override async Task<bool> Dispatch()
{
cts = new CancellationTokenSource();
task = CaseAPI.Dispatch(Arguments, cts.Token);
return await task;
}
CaseAPI
Klasse:
public static async Task<bool> Dispatch(CaseArgs args, CancellationToken ctoken)
{
bool ok = true;
BatchEngine engine = new BatchEngine()
{
Spec = somespec,
CaseName = args.CaseName,
CaseDirectory = args.CaseDirectory
};
ok &= await engine.ExecuteAsync(ctoken);
return ok;
}
BatchEngine
Klasse (hier ist, wo ich die CancellationToken
aufrufen Register
Methode, aber nicht sicher, wo genau zu positionieren, vorausgesetzt, es zählt):
public virtual Task<bool> ExecuteAsync(CancellationToken ctoken)
{
var tcs = new TaskCompletionSource<bool>();
string exe = Spec.GetExecutablePath();
string args = string.Format("--input={0} {1}", Input, ConfigFile);
try
{
var process = new Process
{
EnableRaisingEvents = true,
StartInfo =
{
UseShellExecute = false,
FileName = exe,
Arguments = args,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
WorkingDirectory = CaseDirectory
}
};
ctoken.Register(() =>
{
process.Kill();
process.Dispose();
tcs.SetResult(false);
});
process.Exited += (sender, arguments) =>
{
if (process.ExitCode != 0)
{
string errorMessage = process.StandardError.ReadToEnd();
tcs.SetResult(false);
tcs.SetException(new InvalidOperationException("The batch process did not exit correctly. Error message: " + errorMessage));
}
else
{
File.WriteAllText(LogFile, process.StandardOutput.ReadToEnd());
tcs.SetResult(true);
}
process.Dispose();
};
process.Start();
}
catch (Exception e)
{
Logger.InfoOutputWindow(e.Message);
tcs.SetResult(false);
return tcs.Task;
}
return tcs.Task;
}
Danke für Ihr Interesse und schätzt irgendwelche Ideen zu diesem Thema.
'ctoken.Register' gibt ein Objekt zurück, das im Ereignishandler' Exited' entsorgt werden sollte. –
Dies sollte grundsätzlich funktionieren (abgesehen von einigen Race-Bedingungen, die wahrscheinlich nicht Ihre unmittelbare Problem verursachen). Setzen Sie Haltepunkte auf cts.Cancel und process.Kill, um zu sehen, wo es schief geht. Halbieren. – usr
Können Sie den Code Ihrer IsRunning-Eigenschaft für CaseDispatcher anzeigen? Wo wird das eingestellt? –