Processo di sospensione quando eseguito con .NET Process.Start: cosa c'è che non va?

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

  •  22-07-2019
  •  | 
  •  

Domanda

Ho scritto un wrapper rapido e sporco attorno a svn.exe per recuperare alcuni contenuti e fare qualcosa con esso, ma per alcuni input si blocca occasionalmente e riproducibilmente e non finirà. Ad esempio, una chiamata è svn list:

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

Questa riga di comando funziona perfettamente quando lo faccio da una shell dei comandi, ma si blocca nella mia app. Il mio codice c # per eseguire questo è:

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

Questo richiede tutti i 5000 ms e non finisce mai. L'estensione del tempo non aiuta. In un prompt dei comandi separato, viene eseguito immediatamente, quindi sono abbastanza sicuro che non sia correlato a un tempo di attesa insufficiente. Per altri input, tuttavia, questo sembra funzionare bene.

Ho anche provato a eseguire un cmd.exe separato qui (dove exe è svn.exe e args è la stringa arg originale), ma il blocco si è ancora verificato:

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

Cosa potrei rovinare qui e come posso eseguire il debug di questo processo esterno?

EDIT:

Sto solo ora cercando di risolvere questo problema. Mille grazie a Jon Skeet per il suo suggerimento, che in effetti funziona alla grande. Ho un'altra domanda sul mio metodo di gestione di questo, però, dal momento che sono un principiante multi-thread. Vorrei suggerimenti su come migliorare eventuali carenze evidenti o qualsiasi altra cosa stupida. Ho finito per creare una piccola classe che contiene il flusso stdout, un StringBuilder per contenere l'output e un flag per dire quando è finito. Quindi ho usato ThreadPool.QueueUserWorkItem e ho passato un'istanza della mia 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;
    }
}

Questo sembra funzionare, ma sono dubbioso che questo sia il modo migliore. È ragionevole? E cosa posso fare per migliorarlo?

È stato utile?

Soluzione

Un problema standard: il processo potrebbe essere in attesa che tu legga il suo output. Crea un thread separato da leggere dal suo output standard mentre aspetti che esca. È un po 'una seccatura, ma potrebbe essere questo il problema.

Altri suggerimenti

Jon Skeet ha ragione!
Se non ti dispiace fare il polling dopo aver lanciato il comando svn, prova questo:

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

Ho dovuto rilasciare un exe sulla macchina di un client e usare Process.Start per avviarlo.

L'applicazione chiamante si bloccherebbe - il problema finì per essere il loro computer supponendo che exe fosse pericoloso e impedendo ad altre applicazioni di avviarlo.

Fai clic con il pulsante destro del mouse sull'exe e vai su Proprietà. Premi " Sblocca " verso il fondo accanto all'avviso di sicurezza.

 inserisci qui la descrizione dell'immagine

So che questo è un vecchio post, ma forse questo aiuterà qualcuno. L'ho usato per eseguire alcuni comandi CLI AWS (Amazon Web Services) utilizzando attività .Net TPL.

Ho fatto qualcosa del genere nell'esecuzione del comando che viene eseguita all'interno di un'attività .Net TPL che viene creata nel mio metodo bgwRun_DoWork del lavoratore in background WinForm che tiene un ciclo con while (! bgwRun .CancellationPending) . Questo contiene la lettura dell'output standard dal processo tramite un nuovo thread utilizzando la classe .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
}

So che i miei repository SVN possono essere lenti a volte, quindi forse 5 secondi non sono abbastanza lunghi? Hai copiato la stringa che stai passando al processo da un punto di interruzione, quindi sei sicuro che non ti chieda nulla?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top