7

Ho letto la documentazione per Process.StandardOutput, che ha questa citazione:Modo corretto per gestire l'errore standard e l'output da un programma quando è stato generato tramite la classe Process da C#?

una condizione di deadlock può verificarsi se il processo padre chiama p.WaitForExit prima p.StandardOutput.ReadToEnd e il processo figlio scrive testo sufficiente per riempire il reindirizzato ruscello.

Quindi mi chiedo. Qual è il modo corretto di farlo se temo anche che StandardError possa essere compilato in alcuni scenari?

Devo utilizzare un ciclo di alternare la lettura da standard output ed errori, per evitare sia riempiendo, o si tratta di semplice codice basta:

string error = proc.StandardError.ReadToEnd(); 
string output = proc.StandardOutput.ReadToEnd(); 
bool didFinish = proc.WaitForExit(60000); 

A cura dopo alcune risposte sono state postato

Quindi questo è l'approccio giusto?

var output = new StringBuilder(); 
proc.OutputDataReceived += (s, e) => output.Append(e.Data); 
proc.BeginOutputReadLine(); 
string error = proc.StandardError.ReadToEnd(); 
bool didFinish = proc.WaitForExit(60000); 

E quindi utilizzo il contenuto del stringbuilder solo se il processo è effettivamente terminato.

E 'l'approccio giusto allora?

+0

Controllare la risposta http: // stackoverflow.it/a/7608823/276648 – user276648

risposta

6

Il codice di esempio potrebbe causare un sitout deadlock in cui è stato scritto qualcosa nello StandardOutput e non in StandardError. Il prossimo esempio della documentazione che hai collegato lo dice tanto.

In sostanza, ciò che vorrei raccomandare è utilizzare le letture asincrone su entrambi i flussi per riempire un buffer mentre gli Streams sono scritti, quindi chiamare WaitForExit.

+0

Sì, sono curioso di sapere perché non si utilizza questo metodo come indicato nel MSDN 'È possibile utilizzare operazioni di lettura asincrone per evitare queste dipendenze e il loro potenziale di deadlock. In alternativa, è possibile evitare la condizione di deadlock creando due thread e leggendo l'output di ciascun flusso su una thread separata. – jcolebrand

+0

Modificato nel codice utilizzando BeginOutputReadLine e OutputDataReceived, è possibile dare un'occhiata e vedere se il codice inviato è corretto? –

+0

Questo è quello che ho trovato: http://bitbucket.org/lassevk/mercurial.net/src/728f85d67447/Mercurial.Net/ClientWrapper.cs#cl-111 –

3

Il problema si verifica perché il processo figlio scrive il suo output standard e l'errore standard in una coppia di pipe, che hanno un buffer finito dal sistema operativo. Se il genitore non sta leggendo attivamente entrambi, è possibile che si riempiano. Quando un tubo si riempie, eventuali scritture successive vengono bloccate.

Nel tuo esempio stai leggendo tutto il StandardError quindi tutto il StandardOutput. Funziona correttamente se il processo figlio scrive solo un po 'di dati su e/o StandardOutput. È un problema se il processo figlio vuole scrivere molti dati su StandardOutput. Mentre il processo genitore è in attesa di consumare dati da StandardError, il processo secondario è occupato nel riempimento del buffer StandardOutput.

Il modo più sicuro è di leggere contemporaneamente errore standard in e standard. Ci sono alcuni modi per farlo:

  • Spawn thread separati e chiamare ReadToEnd su ogni
  • Usa BeginRead e EndRead su un thread
  • aggiungere i gestori sulle Process.ErrorDataReceived e Process.OutputDataReceived eventi, quindi chiamare Process.BeginErrorReadLine e Process.BeginOutputReadLine.
Problemi correlati