C standard output waitforexit doesnt wait
Eu uso Process. Start para iniciar um arquivo em lotes. O arquivo em lotes usa o comando START para iniciar vários programas em paralelo e, em seguida, sai. Uma vez que o arquivo de lote é feito Process. HasExited torna-se verdadeira e Process. ExitCode contém o código de saída correto. Mas quando chamo Process. WaitForExit () ele trava / nunca retorna. O código a seguir demonstra o problema. Ele cria um arquivo em lotes, inicia-lo e imprime: Ele deve imprimir: mas ele nunca faz (mesmo que HasExited é verdadeiro e já temos um ExitCode). Notei que isso só acontece quando o arquivo em lotes contém comandos START e quando a saída padrão e / ou erro padrão são redirecionados. Por que WaitForExit () nunca retorna Qual é a maneira certa de esperar por esse processo para sair É seguro para apenas Poll Process. HasExited ou pode resultar em outros problemas PS. Eu só notei que chamar WaitForExit (100000) com um limite de tempo enorme (que definitivamente não expira) retorna imediatamente quando o processo sai. Estranho Sem tempo limite ele trava. Há uma diferença fundamental quando você chamar WaitForExit () sem um tempo limite, ele garante que o stdout / err redirecionados retornaram EOF. Isso garante que você leu toda a saída produzida pelo processo. Nós não podemos ver o que quotonOutputquot faz, mas altas chances de que deadlocks seu programa porque faz algo desagradável como assumindo que seu thread principal é ocioso quando ele é realmente preso em WaitForExit (). Ndash Hans Passant Nov 3 14 at 12:06 Este parece ser um artefato (id dizer bug) na implementação específica do manipulação assíncrona baseada em eventos de StandardOutput e StandardError. Percebi que enquanto eu era capaz de reproduzir facilmente o seu problema, simplesmente executando o código fornecido (excelente exemplo de código, por sinal.)), O processo não realmente pendurar indefinidamente. Em vez disso, ele retornou de WaitForExit () depois que ambos os processos filho que tinham sido iniciados tinham eles mesmos saído. Isso parece ser uma parte intencional da implementação da classe Process. Em particular, no método Process. WaitForExit (), uma vez que tenha terminado esperando no identificador de processo próprio, verifica para ver se um leitor para stdout ou stderr foi criado se assim, e se o valor de tempo limite para o WaitForExit ) É infinita (ie -1), o código realmente aguarda o fim-de-fluxo no leitor (s). Cada leitor respectivo é criado apenas quando o método BeginOutputReadLine () ou BeginErrorReadLine () é chamado. Os fluxos stdout e stderr não são fechados até que os processos filhos tenham fechado. Assim, esperar no final daqueles córregos irá bloquear até que isso aconteça. Que WaitForExit () deve se comportar de forma diferente dependendo se um chamou qualquer um dos métodos que iniciar a leitura baseada em eventos dos fluxos ou não, e especialmente dado que a leitura desses fluxos diretamente não faz com que WaitForExit () se comportam dessa maneira, cria Uma inconsistência na API que torna muito mais difícil de entender e usar. Embora Id pessoalmente chamar isso de um bug, eu suponho que é possível que o implementor (s) da classe Process estão cientes desta inconsistência e criado de propósito. Em qualquer caso, o work-around seria ler StandardOutput e StandardError diretamente em vez de usar a parte baseada em eventos da API. (Embora, claro, se os códigos fossem esperar nesses streams, ver-se-ia o mesmo comportamento de bloqueio até que os processos filhos fecham.) Por exemplo (C, porque eu não sei F bem o suficiente para bofetar um exemplo de código como este juntos rapidamente :)): Espero que o trabalho acima-around ou algo semelhante irá abordar a questão básica youve correr em. Meus agradecimentos ao comentador Niels Vorgaard Christensen por me direcionarem as linhas problemáticas no método WaitForExit (), para que eu pudesse melhorar esse código answer. The parece quase isso: Como você pode ver, o código inicia um processo cmd. exe e Passa para ele o comando que eu quero ser executado. Eu redireccionar StandardError e StandarOutput para lê-los a partir do código. O código lê-los antes do processo. WaitForExit (Timeout) chamar conforme recomendado pela Microsoft (mais sobre isso mais tarde). O problema surge se o comando que eu enviar para cmd. exe nunca termina ou trava indefinidamente. No código eu usei o comando ping - t 8.8.8.8 que, por causa da opção - t, pings o host sem parar. O que acontece O processo cmd. exe junto com o comando ping - t nunca sai e nunca fecha o fluxo stdout e assim o nosso código trava na linha Output. StandardOutput. ReadToEnd () porque não consegue ler todos os fluxos. O mesmo acontece também se um comando em um arquivo em lotes trava por qualquer motivo e, portanto, o código acima poderia trabalhar continuamente por anos e, em seguida, pendurar de repente sem qualquer razão aparente. Antes de eu escrever que seu recomendado para ler fluxos redirecionados antes do processo. WaitForExit (Timeout) chamada, bem isso é especialmente verdadeiro se você usar a assinatura WaitForExit sem o tempo limite. Se você chamar o processo. WaitForExit () antes de ler os fluxos redirecionados: código 2: você pode enfrentar um deadlock se o comando que você anexar ao cmd. exe ou o processo que você está chamando preenche a saída padrão ou erro padrão. Isso porque o nosso código não pode alcançar o processo de saída de linhas. StandardOutput. ReadToEnd () Como uma questão de fato o processo filho (o comando ping ou um arquivo em lotes ou qualquer processo que você está executando) não pode ir se o nosso programa não lê os buffers cheios dos fluxos e isso não pode acontecer porque o código está pendurado em A linha com o processo. WaitForExit () que irá esperar para sempre para o projecto filho para sair. O tamanho padrão de ambos os streams é 4096 bytes. Você pode testar esses dois tamanhos com esses arquivos em lote: O primeiro script grava 4096 bytes na saída padrão e o segundo no erro padrão. Salve um desses em C: testbuffsize. bat e execute o nosso processo de chamada de programa. WaitForExit () antes do processo de saída. StandardOutput. ReadToEnd () como no código 2. Você pode fazê-lo escrevendo CommandResult Resultado ExecuteShellCommandSync (c: testbuffsize. bat, 1000) na linha 13 do código 1. O código não vai cair, mas se você escrever mais um byte em qualquer um dos dois fluxos ele vai transbordar o tamanho do buffer fazendo o programa aguentar. Se você precisa redirecionar e ler a saída padrão ou erro standar a melhor solução é lê-los de forma assíncrona. Uma excelente maneira de fazer isso é proposta por Mark Byers neste thread stackoverflow Como a última coisa, observe que se o processo filho sai apenas porque você usa o processo. WaitForExit (Timeout) assinatura e ele realmente vai em timeout você deve matar o processo cmd. exe e suas possíveis crianças. Sua solução não precisa AutoResetEvent mas você pesquisa. Quando você faz pesquisa em vez de usar o evento (quando eles estão disponíveis), então você está usando CPU sem razão e que indicam que você é um programador ruim. Sua solução é realmente ruim quando comparado com o outro usando AutoResetEvent. (Mas eu não te dei -1 porque você tentou ajudar). Ndash Eric Ouellet Nov 7 14 at 18:38 Eu estava tendo o mesmo problema, mas a razão era diferente. No entanto, aconteceria no Windows 8, mas não no Windows 7. A seguinte linha parece ter causado o problema. A solução era NÃO desativar UseShellExecute. Eu agora recebi uma janela popup Shell, que é indesejável, mas muito melhor do que o programa esperando nada particular acontecer. Então eu adicionei o seguinte work-around para que: Agora, a única coisa que me incomoda é por que isso está acontecendo no Windows 8 em primeiro lugar. Respondido Jan 13 15 at 10:35 Exemplo de uso Implementação
Comments
Post a Comment