Proceso de suspensión cuando se ejecuta con .NET Process.Start & # 8212; que pasa

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

  •  22-07-2019
  •  | 
  •  

Pregunta

Escribí un contenedor rápido y sucio alrededor de svn.exe para recuperar algo de contenido y hacer algo con él, pero para ciertas entradas se cuelga de manera ocasional y reproducible y no termina. Por ejemplo, una llamada es a svn list:

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

Esta línea de comando funciona bien cuando lo hago desde un shell de comandos, pero se cuelga en mi aplicación. Mi código C # para ejecutar esto es:

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

Esto toma los 5000 ms completos y nunca termina. Extender el tiempo no ayuda. En un símbolo del sistema separado, se ejecuta instantáneamente, por lo que estoy bastante seguro de que no está relacionado con un tiempo de espera insuficiente. Para otras entradas, sin embargo, esto parece funcionar bien.

También intenté ejecutar un cmd.exe separado aquí (donde exe es svn.exe y args es la cadena arg original), pero el bloqueo todavía ocurrió:

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

¿Qué podría estar arruinando aquí y cómo puedo depurar este proceso externo?

EDITAR:

Ahora estoy tratando de abordar esto. Mucho gracias a Jon Skeet por su sugerencia, que de hecho funciona muy bien. Sin embargo, tengo otra pregunta sobre mi método para manejar esto, ya que soy un novato con múltiples subprocesos. Quisiera sugerencias para mejorar cualquier deficiencia evidente o cualquier otra cosa tonta. Terminé creando una pequeña clase que contiene la secuencia stdout, un StringBuilder para contener la salida y una bandera para indicar cuándo ha terminado. Luego usé ThreadPool.QueueUserWorkItem y pasé una instancia de mi clase:

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

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

... y ...

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

Esto parece funcionar, pero dudo que esta sea la mejor manera. ¿Es esto razonable? ¿Y qué puedo hacer para mejorarlo?

¿Fue útil?

Solución

Un problema estándar: el proceso podría estar esperando que leas su salida. Cree un hilo separado para leer desde su salida estándar mientras espera que salga. Es un poco doloroso, pero ese puede ser el problema.

Otros consejos

¡Jon Skeet tiene razón en el dinero!

Si no le importa sondear después de iniciar su comando svn, intente esto:

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

Tuve que soltar un exe en la máquina de un cliente y usar Process.Start para iniciarlo.

La aplicación de llamada se colgaría: el problema terminó siendo su máquina suponiendo que el exe era peligroso y evitando que otras aplicaciones lo inicien.

Haga clic derecho en el exe y vaya a propiedades. Presiona "Desbloquear" hacia la parte inferior al lado de la advertencia de seguridad.

 ingrese la descripción de la imagen aquí

Sé que esta es una publicación antigua, pero tal vez esto ayude a alguien. Utilicé esto para ejecutar algunos comandos de la CLI de AWS (Amazon Web Services) utilizando tareas .Net TPL.

Hice algo como esto en la ejecución de mi comando que se ejecuta dentro de una tarea .Net TPL que se crea dentro de mi método bgwRun_DoWork de WinForm que mantiene un bucle con while (! bgwRun .CancellationPending) . Contiene la lectura de la salida estándar del proceso a través de un nuevo subproceso utilizando la clase .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
}

Sé que mis repositorios SVN pueden funcionar lentamente a veces, ¿entonces tal vez 5 segundos no son suficientes? ¿Ha copiado la cadena que está pasando al proceso desde un punto de interrupción para estar seguro de que no le está pidiendo nada?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top