如何解决在为 WaitForExit() 提供最大等待时间时,如何可靠地读取 c# 中进程的完整输出?
考虑以下程序。在这里,我开始一个简单的过程并想处理它的输出。我以为 WaitForExit
返回后会是这种情况,但事实证明,我必须等待一整秒,直到该输出实际到达我的程序中。
static void Main(string[] args)
{
using var p = new Process();
p.StartInfo.FileName = "echo";
p.StartInfo.Arguments = "I apologize for being late";
p.StartInfo.CreateNowindow = false;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
var stdError = new StringBuilder();
var stdOutput = new StringBuilder();
p.ErrorDataReceived += (sender,args) => stdError.AppendLine(args.Data);
p.OutputDataReceived += (sender,args) => stdOutput.AppendLine(args.Data);
p.Start();
p.BeginErrorReadLine();
p.BeginoutputReadLine();
// without the int-parameter here,it works
while (!p.WaitForExit(10000))
Console.WriteLine("still waiting...");
string a = stdOutput.ToString();
string b = stdError.ToString();
Thread.Sleep(1000);
string c = stdOutput.ToString();
string d = stdError.ToString();
Console.WriteLine("output before sleep: " + a);
Console.WriteLine("error before sleep: " + b);
Console.WriteLine("output after sleep: " + c);
Console.WriteLine("error after sleep: " + d);
}
output before sleep:
error before sleep:
output after sleep: I apologize for being late
error after sleep:
在这里,我希望 a
和 c
具有完全相同的值。但事实并非如此。我将如何修改此示例,以便可靠地接收流程的完整输出,但不调用 Thread.Sleep(1000)
?
注意事项:
- 我想要 stdOut 和 stdErr 的可靠完整输出
- 当我使用
p.WaitForExit()
代替p.WaitForExit(10000)
时,一切似乎都正常 - 当对两个流都使用
p.StandardOutput.ReadToEnd()
时,它似乎有效。但有人告诉我by the official documentation,这会导致死锁 - 在对输出使用异步解决方案的同时使用
p.StandardError.ReadToEnd()
时,输出仍然迟到。 - 这不是 Process WaitForExit not waiting 的副本,因为对它们来说
p.WaitForExit()
没有任何参数已经不起作用。此外,他们对输出根本不感兴趣。
解决方法
这里有一个尴尬的实现细节。
打电话
p.WaitForExit();
和
p.WaitForExit(10000);
当实际的本机进程句柄收到信号时,做一些稍微不同的事情。
内部 p.WaitForExit();
调用 p.WaitForExit(-1);
。 -1 在这里很重要。让我们看看我们有什么(代码被简化/解释以显示本质):
public bool WaitForExit(int milliseconds)
{
// init stuff removed
bool flag;
try
{
flag = processWaitHandle.WaitOne(milliseconds,false);
}
finally
{
// here we see our -1 return
if (this.output != null && milliseconds == -1)
{
this.output.WaitUtilEOF();
}
}
return flag;
}
在上面的代码片段中,您可以看到 this.output.WaitUtilEOF();
并调用了一个使用队列的内部 AsyncStreamReader。对 WaitUtilEOF();
的调用基本上是在流上等待引发 EOF 事件。
我找不到其他方法来强制 Process 类进行调用以等待那些 EOF 事件。唯一的选择是不带参数调用 WaitForExit()
。然而,在调用 WaitForExit();
返回后调用 WaitForExit(10000)
不会受到惩罚。
因此,如果您在第一个 WaitForExit(10000)
上超时,但您确定您宁愿等待更长时间,让 AsyncStreamReader 将其拥有的所有数据交给您,请在不带参数的情况下调用 WaitForExit()
两个 AsyncStreamReader 都清空它们的队列,然后将控制权返回给您。这确实意味着,如果您的进程没有结束,您现在就会陷入等待,除非您自己杀死子进程,否则它将永远无法自行解决。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。