【发布时间】:2021-01-12 18:05:01
【问题描述】:
在process.Kill() 之后调用process.Dispose() 或process.Close()(不管是哪一个,在.Dispose 实现中调用'cos .Close)有时会挂起应用程序。
我无法稳定地重现此错误,但有时当WaitForExit 通过超时完成时,应用程序会在process.Close() 命令上挂起。
请建议我,这个问题的原因可能是什么?
注意:
- 我见过similar question。但是没有答案和赞成的评论说,问题的原因可能在细节上,在那个问题上没有提供。所以我添加了更多细节。
- 我也见过linked solution,但我不能使用
ProcessStartInfo.UseShellExecute = true;,因为我需要重定向输出。
对不起,冗长的代码,但我是这样传递的,因为在类似的未回答的问题评论员注意到,没有提供足够的细节(如上所述)
private static async Task<int> RunMethod(string processArguments)
{
// 1. Prepare ProcessStartInfo
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = processArguments;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
// 2. Create process inside using-block to be disposed
using (var proc = new Process())
{
proc.StartInfo = startInfo;
// 3. Subscribe output streams handlers
proc.OutputDataReceived += (sender, outputLine) => { HandleMessage(outputLine); };
proc.ErrorDataReceived += (sender, errorLine) => { HandleMessage(errorLine); };
// 4. Start process
if (!proc.Start())
{
proc.Close();
return -1;
}
// 5. Start the asynchronous read of the standard output stream.
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
// 6. Waiting process to exit with timeout on threadpool to not block UI thread
// Re#er warns me "captured variable `proc` is disposed in the outer scope". But I think it's Ok, 'cos we're awaiting this task inside using block (in next line)
var waitingProcessTask = Task.Run(() => proc.WaitForExit(TIMEOUT), _cancelToken);
bool hasExited = await waitingProcessTask;
// 7. Stop reading streams
// Not sure, these 2 CalncelXxxRead methods are needed. But hope it won't hurt at least
proc.CancelErrorRead();
proc.CancelOutputRead();
// 8. If !hasExited (i.e. TIMEOUT is reached) we kill the process
if (!hasExited)
{
Logger.Debug("0. Before Kill()");
proc.Kill();
proc.Refresh(); // not sure, it's needed
}
// If uncomment next 2 lines, then problem moves here from end of using block
//proc.Close();
//Logger.Debug("1. after .Close call"); // <------------------ This log we don't see sometimes
Logger.Debug("2. last inside using-block");
} // end of using block
Logger.Debug("3. after using-block"); // <------------------ This log we don't see sometimes (if `.Close` wasn't called before)
return 0;
}
【问题讨论】:
-
问题不是处理本身,而是异步流读取行功能导致竞争条件。阅读
Process上的文档,它有很多关于此的警告——如果你使用它们,你有责任编写正确的代码或冻结你的线程。
标签: c# async-await process dispose kill-process