C# 当Process.WaitForExit与硬超时一起使用时,如何等待输出流
这是一种“犯罪研究”,结果非常令人惊讶——至少对我来说是这样 我们正在使用进程对象运行外部命令。我们正在异步捕获标准输出(以及标准错误-为了清晰起见,我已经从示例中删除了它)。这里已经回答了好几次了。代码如下所示,工作正常:C# 当Process.WaitForExit与硬超时一起使用时,如何等待输出流,c#,.net,C#,.net,这是一种“犯罪研究”,结果非常令人惊讶——至少对我来说是这样 我们正在使用进程对象运行外部命令。我们正在异步捕获标准输出(以及标准错误-为了清晰起见,我已经从示例中删除了它)。这里已经回答了好几次了。代码如下所示,工作正常: var process = new Process { StartInfo = { UseShellExecute = false, RedirectStandardOutput = true, FileNam
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
RedirectStandardOutput = true,
FileName = @"...\TestApp.exe"
}
};
process.OutputDataReceived += Process_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
process.OutputDataReceived -= Process_OutputDataReceived;
现在,如果我想给WaitForExit()
添加一个硬超时,该怎么办?简单:有一个重载版本的WaitForExit(int毫秒)
。这样的电话应该可以:
process.WaitForExit(60000);
现在,在某些情况下,这会导致输出捕获不完整。
这不是秘密,至少对微软的开发者来说不是。经过几个小时的研究,我得出结论,WaitForExit的实施肯定有问题。因此,我查看了代码,在Microsoft的实现中发现了以下注释:
// If we have a hard timeout, we cannot wait for the streams
这是我的问题——我已经做了相当多的评估,但没有成功:
如何在
WaitForExit()
上硬超时,同时确保控制台输出捕获完成?您是否尝试在派生类中使用OnExited事件。这可能允许您自己使用等待超时,而不是将其传递到WaitForExit。您的评论将我引向了正确的方向。实际上,我真的不知道要睡多久。但我可以为此添加一个简单的看门狗。由于在我必须开始等待丢失的捕获时,该过程已经完成,因此我可以假设持续触发OutputDataReceived
事件,直到流为空。因此,我所做的就是添加一个秒表
,并在每次OutputDataReceived
事件方法开始时重新启动它。在主代码中,我将调用WaitForExit(60000)
替换为以下代码:
if (process.WaitForExit(60000))
{
while (outputWatch.ElapsedMilliseconds < 20) Thread.Sleep(20);
}
if(process.WaitForExit(60000))
{
while(outputWatch.ElapsedMilliseconds<20)Thread.Sleep(20);
}
好的,这段代码中还有一个线程.Sleep()
。但它肯定会占到0.05%…:) 实际上还有另一个(更好的)解决方案-您可以添加一个AutoResetEvent
,并在从这两个事件接收到的数据为空时进行设置。然后,不仅要检查进程是否已退出,还要检查AutoResetEvent的两个WaitOne
方法是否正确
这里回答了这个问题:不要忽略WaitForExit()的返回值。如果这是真的,那么您知道可能还有一些未读的输出。所以,睡一会儿,让它迎头赶上。睡眠正是我想要消除的。[讽刺]我的拙见是,
Thread.Sleep()
应该会自动弹出一个消息框,告诉你“我是个糟糕的程序员”,每次都要承认这一点。(不,开玩笑,可能有0.05%的情况下,Thread.Sleep()
也被优秀的程序员出于很好的理由使用。)[sarcasm off]这个问题很久很久以前就开始了,I/O重定向肯定是Unix进入Windows最糟糕的功能之一。像那样的黑客不会老。不处理stderr输出hack是另一个您可能会后悔的问题。你必须绕过黑客,这就是需要的。谢谢你的快速拍摄。但这将调用WaitForInputIdle
,它仅适用于具有自己的窗口和事件队列的进程。在我的例子中,我必须运行命令行实用程序。