[Process.ErrorDataReceived在处理完毕后触发?

问题描述 投票:1回答:2

我下面有我的代码,有时在ObjectDisposedException处获得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;
            }
        }
    }
c# process dispose
2个回答
2
投票

[我发现Process事件由于其异步特性(例如,在“ ErrorDataReceived”之前触发了“退出”)。

您还不知道这些事件如何在Process类的掩盖下进行连接,因此您对各个对象的生存期并不了解。到您的处理程序被调用时,Process对象可能已经(并且显然已经被处置)。

我试图与您几乎完全一样地解决这个问题;通过使用AutoResetEvent并从它们各自的事件处理程序中构建Error / Data字符串。

我最终解决此问题的方法是两次调用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)


2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.