Process.StandardOutput使用注意事项

前段时间,经常使用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);
            }
        }

posted on 2010-05-25 16:21  -Anny-  阅读(2795)  评论(0编辑  收藏  举报