当前位置:  开发笔记 > 编程语言 > 正文

使用.NET Process.Start运行时挂起进程 - 出了什么问题?

如何解决《使用.NETProcess.Start运行时挂起进程-出了什么问题?》经验,为你挑选了2个好方法。

我在svn.exe周围写了一个快速而又脏的包装器来检索一些内容并用它做一些事情,但对于某些输入它偶尔会重复挂起并且无法完成.例如,一个调用是svn列表:

svn list "http://myserver:84/svn/Documents/Instruments/" --xml  --no-auth-cache --username myuser --password mypassword

当我从命令shell执行此操作时,此命令行运行正常,但它在我的应用程序中挂起.运行它的我的c#代码是:

string cmd = "svn.exe";
string arguments = "list \"http://myserver:84/svn/Documents/Instruments/\" --xml  --no-auth-cache --username myuser --password mypassword";
int ms = 5000;
ProcessStartInfo psi = new ProcessStartInfo(cmd);
psi.Arguments = arguments;
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
StreamReader output = new StreamReader(proc.StandardOutput.BaseStream, Encoding.UTF8);

proc.WaitForExit(ms);
if (proc.HasExited)
{
    return output.ReadToEnd();
}

这需要整整5000毫秒,永远不会完成.延长时间并没有帮助.在一个单独的命令提示符中,它立即运行,所以我很确定它与等待时间不足无关.但是,对于其他输入,这似乎工作正常.

我也尝试在这里运行一个单独的cmd.exe(其中exe是svn.exe,而args是原始的arg字符串),但仍然发生了挂起:

string cmd = "cmd";
string arguments = "/S /C \"" + exe + " " + args + "\"";

我可以搞砸了什么,我该如何调试这个外部流程?

编辑:

我现在正在解决这个问题.Mucho感谢Jon Skeet的建议,这确实很有效.我有另外一个关于我的处理方法的问题,因为我是一个多线程的新手.我想提出改善任何明显缺陷的建议或其他任何愚蠢的建议.我最终创建了一个包含stdout流的小类,一个用于保存输出的StringBuilder,以及一个告诉它何时完成的标志.然后我使用ThreadPool.QueueUserWorkItem并传入我的类的实例:

ProcessBufferHandler bufferHandler = new ProcessBufferHandler(proc.StandardOutput.BaseStream,
                                                                          Encoding.UTF8);
ThreadPool.QueueUserWorkItem(ProcessStream, bufferHandler);

proc.WaitForExit(ms);
if (proc.HasExited)
{
    bufferHandler.Stop();
    return bufferHandler.ReadToEnd();
}

......而且......

private class ProcessBufferHandler
{
    public Stream stream;
    public StringBuilder sb;
    public Encoding encoding;
    public State state;

    public enum State
    {
        Running,
        Stopped
    }

    public ProcessBufferHandler(Stream stream, Encoding encoding)
    {
        this.stream = stream;
        this.sb = new StringBuilder();
        this.encoding = encoding;
        state = State.Running;
    }
    public void ProcessBuffer()
    {
        sb.Append(new StreamReader(stream, encoding).ReadToEnd());
    }

    public string ReadToEnd()
    {
        return sb.ToString();
    }

    public void Stop()
    {
        state = State.Stopped;
    }
}

这似乎有效,但我怀疑这是最好的方法.这合理吗?我该怎么做才能改善它?



1> Jon Skeet..:

一个标准问题:该过程可能正在等待您阅读其输出.在等待它退出时,创建一个单独的线程来读取其标准输出.这有点痛苦,但这可能是问题所在.


是的,就是这样.只有一个2k输出缓冲区,当你不清空它时它会挂起.BeginOutputReadLine + BeginErrorReadLine解决了它.
您也可以选择不读取标准输出(如果您不需要它).command.StartInfo.RedirectStandardOutput = false为我做了诀窍.

2> Justin Tanne..:

Jon Skeet是对的钱!

如果您在启动svn命令后不介意轮询,请尝试以下操作:

Process command = new Process();
command.EnableRaisingEvents = false;
command.StartInfo.FileName = "svn.exe";
command.StartInfo.Arguments = "your svn arguments here";
command.StartInfo.UseShellExecute = false;
command.StartInfo.RedirectStandardOutput = true;
command.Start();

while (!command.StandardOutput.EndOfStream)
{
    Console.WriteLine(command.StandardOutput.ReadLine());
}


我知道这是四年之后,但我很难理解上面的代码是如何工作的.`command.Start()`是同步的,对吧?如果是这样的话,上面的代码将如何进入下一行?
`Process.Start`是同步的,但是一旦它执行一个命令,它就会返回,留给用户检查命令何时完成.
推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有