我的代码如下,有时会在" errorWaitHandle.Set();"当我的流程实例被处理时,怎么会发生这种情况?
" System.ObjectDisposedException:安全句柄已关闭"
public static int Execute(string filename, string arguments, out string output, out string error, int timeoutInMilliSeconds = Timeout.Infinite)
{
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false), errorWaitHandle = new AutoResetEvent(false))
{
//separate using for process to ensure this is disposed before handles above.
using (System.Diagnostics.Process process = new System.Diagnostics.Process())
{
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
StringBuilder outputSB = new StringBuilder();
StringBuilder errorSB = new StringBuilder();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
outputSB.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
errorSB.AppendLine(e.Data);
}
};
process.Start();
//See http://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// for why we need to read output and error asynch
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (!process.WaitForExit(timeoutInMilliSeconds) ||
!outputWaitHandle.WaitOne(timeoutInMilliSeconds) ||
!errorWaitHandle.WaitOne(timeoutInMilliSeconds))
{
throw new TimeoutException(
string.Format("Executing [{0}] with argument [{1}] didn't finish within timeout {2} milliseconds", filename, arguments, timeoutInMilliSeconds));
}
output = outputSB.ToString();
error = errorSB.ToString();
return process.ExitCode;
}
}
}
答案 0 :(得分:2)
解决方案是将OutputDataReceived和ErrorDataReceived事件订阅到实际方法而不是匿名方法。这样您就可以在Dispose方法中取消订阅。请在此处查看完整代码:
https://github.com/borismod/OsTestFramework/blob/master/OsTestFramework/ProcessExecutor.cs
答案 1 :(得分:2)
我发现Process
事件可能会因意外命令而触发,因为它们具有异步性质(即“Exited”在“ErrorDataReceived”之前被触发)。
您也不知道这些事件是如何在Process类的封面下进行连接的,因此您不了解各种对象的生命周期。当您的处理程序被调用时,Process对象可能已经(并且显然是)被处理掉了。
我试图像你一样处理这个问题;通过使用AutoResetEvent
并在各自的事件处理程序中构建错误/数据字符串。
我最终解决此问题的方法是拨打Process.WaitForExit()
两次:
System.Diagnostics.Process process = new System.Diagnostics.Process()
// Process setup code
if(process.WaitForExit(timeout)){
process.WaitForExit(); // Note the lack of a timeout parameter
// By now all your events should have fired and your strings built
string errorString = errorSB.ToString();
}
MSDN的摘录指出:
标准输出重定向到异步事件时 处理程序,输出处理可能没有 此方法返回时完成。确保异步事件 处理完成后,调用WaitForExit()重载 从此过载中接收到true后不接受任何参数。帮助 确保在Windows窗体中正确处理Exited事件 应用程序,设置SynchronizingObject属性。
来源:https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110)