Я пытаюсь включить опцию Kill
для случая, который выполняется асинхронно с вызывающего потока, как Process
. Мой пример выглядит как ответ @ svick here. Я пытаюсь выполнить рекомендацию @svick в этом post. Но когда я нажимаю на Kill
в пользовательском интерфейсе, он, кажется, ничего не делает (т. Е. Процесс просто выполняется до завершения, как обычно).Остановка процесса с использованием CancellationToken
В соответствии с ответом TimCopenhaver, это ожидается. Но если я прокомментировал это, он все равно ничего не сделает, на этот раз, потому что объект CancellationTokenSource
является нулевым, что является неожиданным, так как я создаю его в методе Dispatch
класса CaseDispatcher
, прежде чем пытаться его убить. Вот мой фрагмент кода:
UI
класс:
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
класс:
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
класс:
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
класс (вот где я призываю CancellationToken
Register
метод, но не знаю точно, где поместить его, предполагая, что это имеет значение):
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;
}
Благодарим Вас за интерес и оценить какие-либо идеи по этому поводу.
'ctoken.Register' возвращает объект, который должен быть удален в обработчике событий« Exited ». –
Это должно в основном работать (помимо нескольких условий гонки, которые, вероятно, не вызывают немедленной проблемы). Поместите точки останова на cts.Cancel и process.Kill, чтобы увидеть, где это происходит не так. Bisect. – usr
Можете ли вы показать код своего свойства IsRunning для CaseDispatcher? Где это устанавливается? –