• Process.StandardOutput使用注意事项 Anny


    前段时间,经常使用C#调用控制台程序,便写了一个通用的方法,起初可以正常工作,直到遇到控制台程序输出内容较多时,发现控制台程序无法自动终止(任务管理器中始终有这个控制台进程,cpu使用率0),查阅msdn,才知道原来出现了死锁现象。

    下面是最初的代码:

       /// <summary>
            /// common method to execute tool
            /// </summary>
            /// <param name="toolFile">tool's path</param>
            /// <param name="args">arguments</param>
            private static void ExecuteTool(string toolFile, string args)
            {
                Process p;
                ProcessStartInfo psi;
                psi = new ProcessStartInfo(toolFile);
                psi.Arguments += args;

                psi.UseShellExecute = false;
                psi.RedirectStandardOutput = true;  //允许重定向标准输出
                psi.CreateNoWindow = true;
                psi.RedirectStandardError = true;
                psi.WindowStyle = ProcessWindowStyle.Hidden;

                p = Process.Start(psi);

                p.WaitForExit();
                p.Close();
            }

    在读取StandardOutput流时,有两种方式,即同步和异步。

    同步方式,会在读取流的一方和写入流的一方形成依赖关系,这种依赖关系形成了死锁的条件。当要写或读足够多的数据时,双方会等待对方写完或者读完,彼此的等待导致了死锁的产生。具体的解释可以参见msdn:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=VS.80).aspx

    如果我们不需要重定向输出,可以将psi.RedirectStandardOutput设置为false。

    如果需要重定向输出,那么必须解决潜在的死锁问题,方法有两个:

    方法一:Call ReadToEnd() before WaitForExit()

    private static void ExecuteTool(string toolFile, string args)
            {
                Process p;
                ProcessStartInfo psi;
                psi = new ProcessStartInfo(toolFile);
                psi.Arguments += args;

                psi.UseShellExecute = false;
                psi.RedirectStandardOutput = true;  //允许重定向标准输出
                psi.CreateNoWindow = true;
                psi.RedirectStandardError = true;
                psi.WindowStyle = ProcessWindowStyle.Hidden;

                p = Process.Start(psi);

        string output = p.StandardOutput.ReadToEnd(); //Call ReadToEnd() before WaitForExit()

                p.WaitForExit();
                p.Close();
            }

    方法二:采用异步方式(适用于同时获取标准输出流和错误流)

    private static void ExecuteTool(string toolFile, string args)
            {
                Process p;
                ProcessStartInfo psi;
                psi = new ProcessStartInfo(toolFile);
                psi.Arguments += args;

                psi.UseShellExecute = false;
                psi.RedirectStandardOutput = true;  //允许重定向标准输出

        psi.RedirectStandardError = true;
                psi.CreateNoWindow = true;
                psi.RedirectStandardError = true;
                psi.WindowStyle = ProcessWindowStyle.Hidden;

                p = Process.Start(psi);

        p.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
                p.BeginOutputReadLine();

                p.WaitForExit();

        if (p.ExitCode != 0)
                {
                    result.Append(p.StandardError.ReadToEnd());
                }           
                p.Close();
            }

      private static void OnDataReceived(object Sender, DataReceivedEventArgs e)
            {
                if (e.Data != null)
                {
                    result.Append(e.Data);
                }
            }

  • 相关阅读:
    失业状态,整理一下近期的面试问题 -- 直面自我
    nginx 学习 查一天不如问一句
    (10)kendo UI使用基础介绍与问题整理——MultiSelect
    kendo常用的实用方法(肯定有用得上的)
    (9)kendo UI使用基础介绍与问题整理——numerictextbox/基础说明
    去掉小数点后无效的0
    cmakelists编写样例
    visio 设计
    优化压测
    (转)语音处理基础知识
  • 原文地址:https://www.cnblogs.com/limei/p/1743707.html
Copyright © 2020-2023  润新知