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
,它仅适用于具有自己的窗口和事件队列的进程。在我的例子中,我必须运行命令行实用程序。