processo de suspensão quando executado com .NET Process.Start - o que está errado?

StackOverflow https://stackoverflow.com/questions/439617

  •  22-07-2019
  •  | 
  •  

Pergunta

Eu escrevi um invólucro rápida e suja ao redor svn.exe para recuperar algum conteúdo e fazer algo com ele, mas para certos insumos ocasionalmente e reprodutível trava e não vai terminar. Por exemplo, uma chamada é a lista svn:

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

Esta linha de comando funciona muito bem quando eu apenas fazê-lo a partir de um shell de comando, mas ele trava em meu aplicativo. Meu c # código para executar isto é:

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();
}

Isso leva o total de 5000 ms e nunca termina. Estendendo o tempo não ajuda. Em um comando separado pronta, ele é executado imediatamente, então eu tenho certeza que ele não está relacionado a um tempo de espera insuficiente. Para outros insumos, no entanto, este parece funcionar bem.

Eu também tentei correr um cmd.exe separado aqui (onde exe é svn.exe e args é a string arg original), mas a pendurar ainda ocorreu:

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

O que eu poderia ser estragar aqui, e como eu posso depurar este material processo externo?

EDIT:

Eu estou apenas agora como se locomover a abordar esta. Mucho graças a Jon Skeet para sua sugestão, que na verdade funciona muito bem. Eu tenho uma outra pergunta sobre o meu método de lidar com isso, porém, desde que eu sou um novato de multi-threaded. Eu gostaria sugestões para melhorar as deficiências gritantes ou qualquer outra forma mudo. I acabou criando uma pequena classe que contém o fluxo de saída padrão, um StringBuilder para manter a saída, e um sinalizador para dizer quando ele for concluído. Então eu usei ThreadPool.QueueUserWorkItem e passou em uma instância da minha classe:

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

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

... e ...

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;
    }
}

Isso parece funcionar, mas estou em dúvida que este é o melhor caminho. Será isto razoável? E o que eu posso fazer para melhorá-lo?

Foi útil?

Solução

Uma questão padrão: o processo poderia estar esperando por você para ler sua saída. Criar um segmento separado para ler a partir de sua saída padrão enquanto você está esperando por ele para sair. É um pouco de dor, mas que pode muito bem ser o problema.

Outras dicas

Jon Skeet é certo sobre o dinheiro!
Se você não se importa de votação depois de lançar o seu comando svn tente o seguinte:

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());
}

Eu tive que soltar um exe na máquina do cliente e usar Process.Start para lançá-lo.

O aplicativo de chamada iria pendurar -. A questão acabou sendo sua máquina assumindo que o exe era perigoso e prevenção de outras aplicações de iniciá-lo

Clique direito a exe e vá para propriedades. Hit "Desbloquear" para a parte inferior ao lado do aviso de segurança.

enter descrição da imagem aqui

Eu sei que este é um post antigo, mas talvez isso irá ajudar alguém. Eu usei isso para executar algumas AWS (Amazon Web Services) CLI comandos usando tarefas .Net TPL.

Eu fiz algo parecido com isso no meu execução do comando que é executado dentro de um TPL Task Net que é criado dentro do meu fundo WinForm método de trabalhador bgwRun_DoWork que segurando um laço com while(!bgwRun.CancellationPending). Este contém a leitura da saída padrão do processo através de um novo segmento usando a classe do .NET ThreadPool.

private void bgwRun_DoWork(object sender, DoWorkEventArgs e)
{
  while (!bgwRun.CancellationPending)
  {
   //build TPL Tasks
   var tasks = new List<Task>();

   //work to add tasks here

   tasks.Add(new Task(()=>{

     //build .Net ProcessInfo, Process and start Process here

     ThreadPool.QueueUserWorkItem(state =>
       {
           while (!process.StandardOutput.EndOfStream)
           {
               var output = process.StandardOutput.ReadLine();
               if (!string.IsNullOrEmpty(output))
               {
                   bgwRun_ProgressChanged(this, new ProgressChangedEventArgs(0, new ExecutionInfo
                   {
                       Type = "ExecutionInfo",
                       Text = output,
                       Configuration = s3SyncConfiguration
                   }));
               }

               if (cancellationToken.GetValueOrDefault().IsCancellationRequested)
               {
                     break;
               }
           }
       });
   });//work Task

   //loop through and start tasks here and handle completed tasks

  } //end while
}

Eu sei que meus repos SVN pode correr devagar, às vezes, por isso talvez 5 segundos não é suficiente? Você copiou a corda que você está passando para o processo a partir de um ponto de ruptura assim que você é positivo que não está pedindo-lhe para alguma coisa?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top