7

Je lis la documentation Process.StandardOutput, qui a cette citation:Manière correcte de gérer l'erreur standard et la sortie d'un programme lorsqu'il est engendré via la classe Process de C#?

Une condition de blocage peut se produire si le processus parent appelle p.WaitForExit avant p.StandardOutput.ReadToEnd et le processus enfant écrit suffisamment de texte pour remplir le redirigée courant.

Alors je me demande. Quelle est la bonne façon de faire cela si j'ai aussi peur que StandardError puisse être rempli dans certains scénarios?

Dois-je utiliser une boucle pour alterner la lecture de la sortie standard et l'erreur, afin d'éviter soit remplir, ou est ce code assez simple:

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

Edité après quelques réponses ont été posté

Donc c'est la bonne approche?

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

Et puis j'utilise le contenu stringbuilder seulement si le processus est terminé.

Est-ce la bonne approche alors?

+0

Vérifiez la réponse http: // stackoverflow.com/a/7608823/276648 – user276648

Répondre

6

Votre code exemple pourrait provoquer une situtation de blocage où il y avait quelque chose d'écrit à l'StandardOutput et non à StandardError. L'exemple suivant de la documentation que vous avez reliée énonce autant. Essentiellement, ce que je recommanderais, est d'utiliser les lectures asynchrones sur les deux flux pour remplir un tampon que les flux sont écrits, puis appelez WaitForExit.

+0

Oui, je suis curieux de savoir pourquoi vous n'utilisez pas cette méthode comme indiqué dans le MSDN 'Vous pouvez utiliser des opérations de lecture asynchrones pour éviter ces dépendances et leur potentiel de blocage. Alternativement, vous pouvez éviter la condition de blocage en créant deux threads et en lisant la sortie de chaque flux sur un thread séparé. – jcolebrand

+0

Édité dans le code en utilisant BeginOutputReadLine et OutputDataReceived, pouvez-vous jeter un oeil et voir si le code posté est correct? –

+0

Voici ce que j'ai fini avec: http://bitbucket.org/lassevk/mercurial.net/src/728f85d67447/Mercurial.Net/ClientWrapper.cs#cl-111 –

3

Le problème est dû au fait que le processus enfant écrit sa sortie standard et son erreur standard dans une paire de canaux, qui reçoivent un tampon fini par le système d'exploitation. Si le parent ne lit pas tous les deux activement, ils sont susceptibles de se remplir. Lorsqu'un tuyau se remplit, toute écriture ultérieure est bloquée. Dans votre exemple, vous lisez StandardError puis StandardOutput. Cela fonctionne correctement si le processus enfant écrit seulement un peu de données à StandardError et/ou StandardOutput. C'est un problème si le processus enfant veut écrire beaucoup de données à StandardOutput. Pendant que le processus parent attend de consommer des données de StandardError, le processus enfant est occupé à remplir le tampon StandardOutput.

Le moyen le plus sûr est de lire simultanément les erreurs standard et les erreurs standard. Il y a quelques façons de le faire:

  • threads séparés Spawn et appellent ReadToEnd sur chaque
  • Utilisez BeginRead et EndRead sur un fil
  • Ajouter des gestionnaires sur les événements Process.ErrorDataReceived et Process.OutputDataReceived, puis appelez Process.BeginErrorReadLine et Process.BeginOutputReadLine.
Questions connexes