的过程.在处置进程后触发ErrorDataReceived

本文关键字:ErrorDataReceived 进程 过程 | 更新日期: 2023-09-27 18:11:24

我的代码如下,有时得到ObjectDisposedExceptionerrorWaitHandle.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;
            }
        }
    }

的过程.在处置进程后触发ErrorDataReceived

我发现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)

解决方案是将OutputDataReceivedErrorDataReceived事件订阅到实际方法,而不是匿名方法。这样您就可以在Dispose()方法中取消订阅。

查看完整代码:

https://github.com/borismod/OsTestFramework/blob/master/OsTestFramework/ProcessExecutor.cs

相关文章:
  • 没有找到相关文章