的过程.在处置进程后触发ErrorDataReceived
本文关键字:ErrorDataReceived 进程 过程 | 更新日期: 2023-09-27 18:11:24
我的代码如下,有时得到ObjectDisposedException
在errorWaitHandle.Set();
。
当我的流程实例被处置时,怎么会发生这种情况?
系统。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;
}
}
}
我发现Process
事件可以以意外的顺序触发,因为它们的异步性质(即"退出")
您也不知道这些事件是如何在Process类的掩护下连接起来的,因此您并不真正知道各种对象的生存期。在调用处理程序时,Process对象可能已经(显然已经)被处置了。
我试图用几乎和你一样的方法来解决这个问题;通过使用AutoResetEvent
's并从各自的事件处理程序中构建错误/数据字符串。
我最终修复这个问题的方式是通过调用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窗体中正确处理退出事件
设置SynchronizingObject属性。来源:https://msdn.microsoft.com/en-us/library/ty0d8k56 (v = vs.110)
解决方案是将OutputDataReceived
和ErrorDataReceived
事件订阅到实际方法,而不是匿名方法。这样您就可以在Dispose()
方法中取消订阅。
查看完整代码:
https://github.com/borismod/OsTestFramework/blob/master/OsTestFramework/ProcessExecutor.cs