C# 是什么破坏了我的进程。StartInfo.OutputDataReceived回调过早?
以下问题发生在.NET Framework v3.5上。不知道它是否适用于v4* 为了捕获某些进程的标准输出,我成功地使用了C# 是什么破坏了我的进程。StartInfo.OutputDataReceived回调过早?,c#,multithreading,process,stdout,stderr,C#,Multithreading,Process,Stdout,Stderr,以下问题发生在.NET Framework v3.5上。不知道它是否适用于v4* 为了捕获某些进程的标准输出,我成功地使用了p.StartInfo.UseShellExecute=false和p.StartInfo.RedirectStandardOutput=true和连接到p.StartInfo.OutputDataReceived+=…;的事件处理程序。然后我调用p.Start()然后p.BeginOutputReadLine()然后p.WaitForExit() 到目前为止一切顺利。正如
p.StartInfo.UseShellExecute=false代码>和p.StartInfo.RedirectStandardOutput=true代码>和连接到p.StartInfo.OutputDataReceived+=…;的事件处理程序代码>。然后我调用p.Start()代码>然后p.BeginOutputReadLine()代码>然后p.WaitForExit()代码>
到目前为止一切顺利。正如预期的那样,我在事件处理程序中逐行获取所有标准输出
我必须引入一个超时,而不是WaitForExit()
,因为一些进程不可预测地在stdin触发输入请求(例如,你确定吗?[y/n]),导致死锁,我会永远等待,他们也会这样做
我尝试的第一件事是在(!p.HasExited&&DateTime.Now代码>其中timeoutmoment
是proc.Start()
后2分钟。这就是我遇到问题的时候。非常一致的是,该代码适用于最多生成几百行stdout的调用,但对于一个生成大约7500行stdout的调用,它会中断。发生的是proc.WaitForExit(200)代码>线程退出,而
当我的OutputDataReceived
事件处理程序只被调用了约7300行时(这个数字同样非常一致,在测试之间只变化了+/-1),其余的stdout行不再调用处理程序,因此我丢失了它们
奇怪的是,如果我避免使用WaitForExit(200)
而在(!p.HasExited&&DateTime.Now,问题就不会出现代码>(以下代码中未显示)。当我发布这个问题时,我非常确定使用Sleep(1000)
可以避免这个问题,但我错了。它像那样工作了几十次,然后就没有了,它开始表现得就像我选中WaitForExit(200)
时一样
我现在推测这个问题的原因是(1)我处理每个OutputDataReceived
回调的时间太长。我注意到,当我在事件处理程序中添加一个条件断点时,问题变得更加严重,这大大延长了方法的执行时间。我现在可以通过简单地添加3x Debug.writeline而不使用条件断点来重现问题;另外(2)在系统有机会对我的事件处理程序执行所有回调之前,我访问haseexit
/WaitForExit(200)
,不知何故,我的上下文被破坏了。现在,我在p.Start()
之后和访问任何p.*
方法之前,执行一个盲System.Threading.Thread.Sleep(30000)
,并获得所有回调。当我使用WaitForExit()
时,似乎我可以花多少时间来处理每个回调,但我仍然可以得到所有回调
有人能更明白这一点吗
代码:
private int\u execOsProc(
ProcessStartInfo Psi
,字符串SecInsensArgs
,TextWriter ExtraStdOutAndErrTgt
,布尔输出ExtrastAutoly
)
{
var pr=新流程();
pr.StartInfo=Psi;
pr.StartInfo.UseShellExecute=false;
pr.StartInfo.RedirectStandardOutput=pr.StartInfo.RedirectStandardError=true;
pr.StartInfo.CreateNoWindow=true;
var ol=新数据接收到的数据处理器(此.\u stdOutDataReceived);
var el=新数据接收到的数据处理程序(此.\u stdErrDataReceived);
pr.OutputDataReceived+=ol;
pr.ErrorDataReceived+=el;
尝试
{
__logger.Debug(“正在执行:\”“+pr.StartInfo.FileName+”\”“+secinsargs);
如果(ExtraStdOutAndErrTgt==null)
{
这是.uu outputoExtrastAutoly=false;
}
其他的
{
这是.\uu extraStdOutAndErrTgt=extraStdOutAndErrTgt;
这是.uu outputExtrastAutoly=outputExtrastAutoly;
}
pr.Start();
pr.BeginOutputReadLine();
pr.BeginErrorReadLine();
var startmom=DateTime.Now;
var timeoutmom=startmom.AddMinutes(2);
而(!pr.hasExit&&DateTime.Nowvar startmom = DateTime.Now;
var timeoutmom = startmom.AddMinutes(2);
while (!pr.HasExited && DateTime.Now < timeoutmom)
pr.WaitForExit(200);
if (pr.HasExited)
{
WaitForExit();//Ensure that redirected output buffers are flushed
pr.CancelOutputRead();
pr.CancelErrorRead();
__logger.Debug("Execution finished with exit status code: " + pr.ExitCode);
return pr.ExitCode;
}
else
{
pr.CancelOutputRead();
pr.CancelErrorRead();
__logger.Debug("Timeout while waiting for execution to finish");
pr.Kill();
return -100;
}