2009-09-25 16 views
7

Ho read che questa porzione di codice può causare deadlock:Problemi DeadLock in Process.StandardOutput.ReadToEnd();

Process p = new Process(); 

p.StartInfo.UseShellExecute = false; 
p.StartInfo.RedirectStandardOutput = true; 
p.StartInfo.FileName = "Write500Lines.exe"; 
p.Start(); 
p.WaitForExit(); 
string output = p.StandardOutput.ReadToEnd(); 

Perché

una condizione di deadlock può causare il processo padre chiama p.WaitForExit prima p.StandardOutput.ReadToEnd e il processo figlio scrive testo sufficiente per riempire il flusso reindirizzato. Il processo padre aspetterebbe indefinitamente per l'uscita del processo figlio. Il processo figlio aspetterebbe a tempo indeterminato affinché il genitore possa leggere dallo stream standardOutput completo .

Ma non so perché. Voglio dire, in questo caso qui, qual è il processo genitore, e qual è il bambino?

+1

Potresti essere interessato a [questo post] (http://www.codeducky.org/process-handling-net), che spiega deadlocking e altre complessità del funzionamento con flussi di processo .NET. – ChaseMedallion

risposta

11

In breve questo è ciò che può accadere:

di applicazione A (il vostro codice di cui sopra) si avvia processo figlio B e reindirizza standard output. Quindi A attende che il processo B esca. Mentre A attende che B esca, B produce output nel flusso di output (che A ha reindirizzato). Questo flusso ha una dimensione del buffer limitata. Se il buffer si riempie, deve essere svuotato affinché B possa continuare a scriverlo. Poiché A non sta leggendo finché non è uscito B, si può finire in una situazione in cui B aspetterà che il buffer di output venga svuotato, mentre A attenderà che B esca. Entrambi si aspettano l'un l'altro per agire, e tu hai una situazione di stallo.

È possibile provare il seguente codice per dimostrare il problema:

ProcessStartInfo psi = new ProcessStartInfo(); 
psi.FileName = "cmd"; 
psi.Arguments = @"/c dir C:\windows /s"; 
psi.RedirectStandardOutput = true; 
psi.UseShellExecute = false; 
Process p = Process.Start(psi); 
p.WaitForExit(); 
string output = p.StandardOutput.ReadToEnd(); 

Questo (moste probabile) produrre la situazione in cui il flusso di uscita è pieno in modo che il processo figlio (in questo caso "cmd") attenderà per essere cancellato, mentre il codice sopra attenderà che cmd termini.

+0

Grazie per la tua lucida spiegazione. – Graviton

+0

Quindi ... come posso eseguire un processo come 'sqlcmd.exe' con alcuni argomenti per non più di 5 minuti e leggere tanto di stdout e stderr che posso acquisire? Non sono riuscito a trovare un modo semplice e pulito per farlo. –

+0

spiegazione eccellente! –

0

Il processo padre è quello che chiama p.Start(). Immagino che questa sia la tua applicazione (il chiamante). Il processo figlio è p o in altre parole, il chiamato.