【发布时间】:2016-06-20 21:20:42
【问题描述】:
我正在尝试为从调用线程异步运行的情况启用Kill 选项,例如Process。我的示例看起来像@svick 的答案here。我正在尝试在此post 中实施@svick 的建议。但是当我在 UI 中单击 Kill 时,它似乎什么也没做(即,该过程像往常一样简单地运行到完成)。
根据@TimCopenhaver 的回复,这是意料之中的。但是,如果我将其注释掉,它仍然没有做任何事情,这一次是因为 CancellationTokenSource 对象 cts 为空,这是出乎意料的,因为我在尝试之前在 CaseDispatcher 类的 Dispatch 方法中实例化了它杀死它。这是我的代码 sn-p:
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 上放置断点,看看哪里出错了。平分。
-
你能显示你的 IsRunning 属性的代码 CaseDispatcher 吗?这是在哪里设置的?
-
@TimCopenhaver:我刚刚包含了访问器。好点,看起来我什至没有进入杀戮。可能是因为此时尚未分配私有任务对象(结果为空),因为批处理显然尚未完成。无论用户何时调用 Kill ,我都会调用 cts.Cancel() ,看看它是否能让我更进一步。
-
@usr:你说得对,我测试它工作正常,现在我的问题主要是外围问题,正如 Tim Copenhaver 所指出的那样
标签: c# asynchronous process kill