ProcessStartInfo suspendus sur “WaitForExit”? Pourquoi?
J'ai le code suivant:
info = new System.Diagnostics.ProcessStartInfo("TheProgram.exe", String.Join(" ", args));
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd()); //need the StandardOutput contents
Je sais que la sortie du processus, je suis de départ est d'environ 7MO de long. De l'exécuter dans la console Windows fonctionne très bien. Malheureusement, par programmation, cela se bloque indéfiniment à WaitForExit. Notez également ce code ne raccrochez PAS pour les petites sorties (comme 3KB).
Est-il possible qu'à l'interne, StandardOutput dans ProcessStartInfo ne pouvez pas le tampon de 7MO? Si oui, que dois-je faire à la place? Si non, ce que je fais mal?
- solution définitive avec le code source complet à ce sujet ?
- Je rencontre le même problème et ce comment j'ai pu le résoudre stackoverflow.com/questions/2285288/...
- Oui, la solution finale: permuter les deux dernières lignes. C'est dans le manuel.
- à partir de msdn: L'exemple de code permet d'éviter une situation de blocage en appelant p.StandardOutput.ReadToEnd avant p.WaitForExit. Une condition de blocage peut se produire si le processus parent appelle p.WaitForExit avant p.StandardOutput.ReadToEnd et le processus de l'enfant écrit assez de texte pour remplir la redirection de flux. Le processus parent serait d'attendre indéfiniment le processus de l'enfant à la sortie. Le processus de l'enfant serait d'attendre indéfiniment pour les parents à lire à partir de la pleine StandardOutput flux.
- c'est un peu embêtant comment complexe est de le faire correctement. A été heureux de travailler autour d'elle avec de plus simple ligne de commande redirige > outputfile 🙂
Vous devez vous connecter pour publier un commentaire.
Le problème est que si vous rediriger
StandardOutput
et/ouStandardError
la mémoire tampon interne peut devenir complet. Quelle que soit la commande que vous utilisez, il peut être un problème:StandardOutput
le processus peut bloquer à essayer d'écrire, de sorte que le processus ne se termine jamais.StandardOutput
à l'aide de ReadToEnd puis votre processus peut bloquer si le processus ne se referme jamaisStandardOutput
(par exemple si elle ne se termine, ou si elle est bloquée par écrit àStandardError
).La solution est d'utiliser asynchrone lit pour s'assurer que le tampon de ne pas obtenir le plein. Pour éviter toute blocages et de recueillir toutes les données de sortie à partir de deux
StandardOutput
etStandardError
vous pouvez faire ceci:EDIT: Voir les réponses ci-dessous pour savoir comment éviter une ObjectDisposedException si le délai d'attente se produit.
process.Start()
. Quelqu'un at-il vécu cela?using
consolidés pour les gestionnaires d'événements doivent être au-dessus leusing
déclaration pour le processus lui-même?e.Data
indique la fin du flux? Je ne trouve pas que la documentation de n'importe où.process.Start()
etprocess.BeginOutputReadLine()
🙁int processTimeout = timeout == Timeout.Infinite ? Int32.MaxValue : timeout;
La la documentation pour
Process.StandardOutput
dit de lire avant de vous attendez autrement vous pouvez impasse, extrait copié ci-dessous:RedirectStandardOutput = true;
et n'utilisez pasp.StandardOutput.ReadToEnd();
vous obtenez un blocage/de blocage.Marque Byers réponse est excellente, mais je voudrais juste ajouter les éléments suivants: la OutputDataReceived et ErrorDataReceived délégués doivent être supprimés avant la outputWaitHandle et errorWaitHandle sont disposées. Si le processus se poursuit pour la sortie des données après le délai a été dépassé et puis s'arrête, le outputWaitHandle et errorWaitHandle variables seront accessibles après avoir été éliminés.
(Pour info j'ai dû ajouter cette mise en garde comme une réponse que je n'ai pas de commentaires sur son post.)
Le problème avec les non gérée ObjectDisposedException se produit lorsque le processus est dépassé. Dans de tels cas, les autres parties de la condition:
ne sont pas exécutées. J'ai résolu ce problème de façon suivante:
output
eterror
àoutputBuilder
? Quelqu'un peut-veuillez fournir une réponse complète qui fonctionne?C'est un plus moderne awaitable, Task Parallel Library (TPL) en fonction de la solution pour .NET 4.5 et supérieur.
Exemple D'Utilisation
Mise en œuvre
Rob répondu et m'a sauvé plus de quelques heures d'essais. Lire la sortie/erreur de la mémoire tampon avant de l'attente:
WaitForExit()
?ReadToEnd
ou des méthodes similaires (commeStandardOutput.BaseStream.CopyTo
) sera de retour après TOUS les données sont lues. rien ne viendra aprèsNous avons ce problème aussi bien (ou une variante).
Essayez ce qui suit:
1) Ajouter un délai d'attente de p.WaitForExit(nnnn); où nnnn est en millisecondes.
2) Mettre le ReadToEnd appel avant que le WaitForExit appel. Cette est ce que nous avons vu MME recommander.
De crédit à EM0 pour https://stackoverflow.com/a/17600012/4151626
L'autre des solutions (y compris EM0 est) toujours dans l'impasse pour mon application, en raison de délais d'attente et l'utilisation des deux StandardOutput et StandardError par l'application générée. Voici ce qui a fonctionné pour moi:
Edit: ajout de l'initialisation de l'StartInfo à l'exemple de code
Je l'ai résolu de cette façon:
J'ai redirigé la fois d'entrée, de sortie et d'erreur et manipulés lecture à partir de la sortie d'erreur et de flux.
Cette solution fonctionne pour SDK 7 - 8.1, à la fois pour Windows 7 et Windows 8
Ce post, peut-être obsolète, mais j'ai trouvé la cause principale pour laquelle il accroche souvent est due à un débordement de pile pour la redirectStandardoutput ou si vous avez redirectStandarderror.
Que les données de sortie ou les données d'erreur est grand, il sera la cause d'un plantage de temps car il est toujours en cours de traitement pour une durée indéterminée.
donc, pour résoudre ce problème:
J'ai essayé de faire une classe qui permettrait de résoudre votre problème à l'aide asynchrone flux en lecture, en tenant compte de la Marque Byers, Rob, stevejay réponses. Ce faisant, j'ai réalisé qu'il y est un bug lié au processus asynchrone flux de sortie en lecture.
J'ai signalé ce bug chez Microsoft: https://connect.microsoft.com/VisualStudio/feedback/details/3119134
Résumé:
Vous êtes probablement mieux à l'aide de lecture asynchrone comme suggéré par d'autres utilisateurs de votre cas. Mais vous devez être conscient que vous pourriez manquer des informations en raison de la condition de course.
Aucune des réponses ci-dessus est faire le travail.
Rob solution se bloque et 'A' obtenir la solution disposé d'exception.(J'ai essayé les "solutions" de l'autre des réponses).
J'ai donc décidé de proposer une autre solution:
Ce code de débogage et fonctionne parfaitement.
GetProcessOutputWithTimeout
méthode.Introduction
Actuellement accepté de répondre ne fonctionne pas (throws exception) et il y a aussi beaucoup de solutions de contournement, mais pas de code complet. C'est évidemment de perdre beaucoup de temps, car c'est une question populaire.
Combinant la Marque Byers réponse et Karol Tyl réponse, j'ai écrit plein de code basé sur la façon dont je veux utiliser le Processus.Méthode de démarrage.
Utilisation
Je l'ai utilisé pour créer la boîte de dialogue de progression autour de commandes git. C'est de cette façon que j'ai utilisé:
En théorie, vous pouvez également combiner stdout et stderr, mais je n'ai pas testé.
Code
Je sais que c'est le souper vieux, mais, après la lecture de cette page entière aucune des solutions a été de travailler pour moi, bien que je n'ai pas essayer Muhammad Rehan car le code est un peu dur à suivre, bien que je suppose qu'il était sur la bonne voie. Quand je dis qu'il ne fonctionne pas ce n'est pas tout à fait vrai, parfois ça marcherait bien, je suppose que c'est quelque chose à voir avec la longueur de la sortie avant un EOF marque.
De toute façon, la solution qui a fonctionné pour moi a été d'utiliser des threads différents pour lire la StandardOutput et StandardError et écrire les messages.
Espère que cela aide quelqu'un, qui pensaient que cela pourrait être si dur!
sw.FlushAsync(): Object is not set to an instance of an object. sw is null.
Comment/où devraitsw
être défini?Après la lecture de tous les posts ici, je me suis installé sur les états solution de Marko Avlijaš.
Cependant, il n'a pas de résoudre tous mes problèmes.
Dans notre environnement, nous avons un Service Windows qui est planifiée pour s'exécuter à des centaines de .chauve-souris .cmd .exe,... etc. les fichiers qui ont accumulé au fil des ans et ont été écrits par de nombreuses personnes différentes et dans des styles différents. Nous n'avons aucun contrôle sur l'écriture des programmes & des scripts, nous sommes responsable de la planification, l'exécution, et des rapports sur les succès/échec.
Donc j'ai essayé à peu près toutes les suggestions ici avec différents niveaux de succès. Marko réponse était presque parfait, mais lorsqu'il est exécuté en tant que service, il n'a pas toujours de saisir la sortie standard stdout. Je n'ai jamais pu le bas de la pourquoi pas.
La seule solution que nous avons trouvé qui fonctionne dans TOUS nos cas, est-ce : http://csharptest.net/319/using-the-processrunner-class/index.html
Solution de contournement j'ai fini d'utilisation afin d'éviter toute la complexité:
J'ai donc créer un fichier temporaire, de rediriger la fois la production et de l'erreur en utilisant des
> outputfile > 2>&1
et puis il suffit de lire le fichier une fois le processus terminé.Les autres solutions sont très bien pour les scénarios où vous souhaitez faire d'autres choses avec la sortie, mais pour des choses simples cela évite beaucoup de complexité.
J'chose que ce qui est simple et la meilleure approche (nous n'avons pas besoin
AutoResetEvent
):.FileName = Path + @"\ggsci.exe" + @" < obeycommand.txt"
pour simplifier votre code de trop? Ou peut-être quelque chose d'équivalent à"echo command | " + Path + @"\ggsci.exe"
si vous ne voulez vraiment pas à séparer obeycommand.txt fichier.Je pense qu'avec asynchrone, il est possible d'avoir une solution plus élégante et de ne pas avoir de blocages, même lors de l'utilisation de deux standardOutput et standardError:
Il est base sur Marque Byers réponse.
Si vous n'êtes pas dans une méthode asynchrone, vous pouvez utiliser
string output = tStandardOutput.result;
au lieu deawait
Nous rappelons l'exemple de code posté ici le redirecteur et l'autre programme de la redirection. Si c'était moi, alors je serais probablement écrire un test redirigé programme qui peut être utilisé pour reproduire le problème.
Je l'ai fait. Pour les données de test, j'ai utilisé le ECMA-334 Langage C# Specificationv PDF; il est d'environ 5 MO. Ce qui suit est la partie importante.
La données. datasize valeur ne correspond pas à la taille réelle du fichier, mais qui n'a pas d'importance. Il n'est pas clair si un fichier PDF utilise toujours les deux CR et LF à la fin des lignes, mais qui n'a pas d'importance pour cela. Vous pouvez utiliser tout autre fichier texte afin de le tester.
À l'aide de l'exemple de code de redirection se bloque quand j'écris de la grande quantité de données, mais pas quand j'écris une petite quantité.
J'ai essayé beaucoup de quelque sorte de tracer l'exécution de ce code et je ne pouvais pas. J'ai commenté les lignes du programme de redirection personnes handicapées de la création d'une console pour la redirection de programme pour essayer d'obtenir une seconde fenêtre de la console, mais je ne pouvais pas.
Puis j'ai trouvé Comment faire pour démarrer une application console dans une nouvelle fenêtre, le parent de la fenêtre ou sans fenêtre. Donc, apparemment, nous ne pouvons pas (facilement) ont une console séparée lorsqu'un programme console démarre un autre programme de console sans ShellExecute et depuis ShellExecute ne prend pas en charge la redirection de nous devons partager une console, même si l'on précise pas de fenêtre pour les autres processus.
Je suppose que si la redirection de programme remplit un tampon quelque part, alors il faut attendre pour que les données puissent être lues et si aucune donnée n'est lu que par le redirecteur c'est une impasse.
La solution est de ne pas utiliser ReadToEnd et à lire les données tandis que les données est en train d'être écrit, mais il n'est pas nécessaire d'utiliser des lectures asynchrones. La solution peut être assez simple. Les ouvrages suivants, pour moi le 5 MB PDF.
Une autre possibilité est d'utiliser un programme graphique pour faire de la redirection. Le code précédent fonctionne dans une application WPF à l'exception évidente des modifications.
J'ai eu le même problème, mais la raison en était différent. Il serait cependant se produire sous Windows 8, mais pas sous Windows 7. La ligne suivante semble avoir causé le problème.
La solution était de ne PAS désactiver UseShellExecute. J'ai reçu une Coque fenêtre pop-up, ce qui est indésirable, mais beaucoup mieux que le programme attend rien de particulier à se produire. J'ai donc ajouté à la solution de contournement pour que:
Maintenant la seule chose qui me tracasse est pourquoi ce qui se passe sous Windows 8, en premier lieu.
UseShellExecute
être défini à false si vous voulez rediriger la sortie.