понедельник, 7 мая 2018 г.

Waitforexit c # trava


o log de Walter.
. Escrevendo enquanto aprende.
Sexta-feira, 18 de novembro de 2011.
Process. WaitForExit (Int32) trava o problema.
Como você pode ver, o código inicia um processo "cmd. exe" e passa para ele o comando que eu quero executar.
No código eu usei o comando ping - t 8.8.8.8 que, por causa da opção - t, pinga o host sem parar. O que acontece? O processo "cmd. exe" juntamente com o comando ping - t nunca sai e nunca fecha o fluxo stdout e, portanto, o código trava no Output = process. StandardOutput. ReadToEnd (); linha porque não pode ter sucesso lendo todo o fluxo.
O mesmo acontece também se um comando em um arquivo de lote for interrompido por algum motivo e, portanto, o código acima poderia funcionar continuamente por anos e, em seguida, travar repentinamente sem nenhum motivo aparente.
Você pode experimentar um deadlock se o comando que você anexar a "cmd. exe" ou o processo que você está chamando preencher a saída padrão ou o erro padrão. Isso porque nosso código não pode alcançar as linhas.
Na verdade, o processo filho (o comando ping ou um arquivo em lote ou qualquer outro processo que você esteja executando) não pode continuar se nosso programa não ler os buffers preenchidos dos fluxos e isso não pode acontecer porque o código está pendurado na linha com o processo. WaitForExit (), que irá esperar eternamente para o projeto filho sair.
O tamanho padrão de ambos os fluxos é de 4096 bytes. Você pode testar esses dois tamanhos com esses arquivos em lotes:

Waitforexit c # trava
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.
Quando o arquivo em lote estiver concluído, Process. HasExited se tornará true e Process. ExitCode conterá o código de saída correto.
Mas quando eu chamo Process. WaitForExit () ele trava / nunca retorna.
O seguinte trecho de código demonstra o problema. Cria um arquivo de lote, inicia e imprime:
Em seguida, deve imprimir:
. mas isso nunca acontece (embora HasExited seja verdadeiro e já tenhamos um ExitCode).
Notei que isso só acontece quando o arquivo de lote 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 é o caminho certo para esperar por tal processo sair?
É seguro apenas pesquisar Process. HasExited ou isso pode resultar em outros problemas?
PS: Acabei de notar que chamar WaitForExit (100000) com um tempo limite enorme (que definitivamente não expira) retorna imediatamente quando o processo termina. Estranho Sem tempo limite, trava.
Este parece ser um artefato (eu diria "bug") na implementação específica da manipulação assíncrona baseada em evento de StandardOutput e StandardError.
Notei que, embora eu fosse capaz de reproduzir facilmente o seu problema, simplesmente executando o código que você forneceu (excelente exemplo de código, a propósito! :)), o processo não parou de funcionar indefinidamente. Em vez disso, retornou de WaitForExit () uma vez que ambos os processos filhos que haviam sido iniciados tinham sido encerrados.
Esta parece ser uma parte intencional da implementação da classe Process. Em particular, no método Process. WaitForExit (), uma vez terminada a espera do próprio identificador de processo, ele verifica se um leitor para stdout ou stderr foi criado; se assim, e se o valor de tempo limite para a chamada WaitForExit () é "infinito" (ou seja, -1), o código, na verdade, aguarda o fim de fluxo no (s) leitor (es).
Cada leitor respectivo é criado apenas quando o método BeginOutputReadLine () ou BeginErrorReadLine () é chamado. Os fluxos stdout e stderr não estão fechados até que os processos filhos tenham sido fechados. Então, esperar no final desses fluxos irá bloquear até que isso aconteça.
Que WaitForExit () deve se comportar de maneira diferente dependendo se alguém chamou ou um dos métodos que iniciam a leitura baseada em eventos dos streams ou não, e especialmente porque ler esses streams diretamente não faz com que WaitForExit () se comporte dessa maneira, cria uma inconsistência na API que torna muito mais difícil de entender e usar. Embora eu pessoalmente chame isso de bug, suponho que seja possível que o (s) implementador (es) da classe Process estejam cientes dessa inconsistência e a tenham criado intencionalmente.
Em qualquer caso, a solução alternativa seria ler StandardOutput e StandardError diretamente, em vez de usar a parte baseada em eventos da API. (Embora, é claro, se o código de alguém esperasse nesses fluxos, a pessoa veria o mesmo comportamento de bloqueio até que a criança processasse próximo.)
Por exemplo (C #, porque eu não sei F # bem o suficiente para bater um exemplo de código como este juntos rapidamente :)):
Espero que a solução acima ou algo similar resolva o problema básico que você encontrou. Meus agradecimentos ao comentarista Niels Vorgaard Christensen por me direcionar para as linhas problemáticas no método WaitForExit (), para que eu pudesse melhorar essa resposta.

Exemplo de uso.
Eu resolvi assim:
Eu redirecionei tanto a entrada, saída e erro e lidou com a leitura de fluxos de saída e erro. Essa solução funciona para o SDK 7- 8,1, tanto para o Windows 7 quanto para o Windows 8.
Eu tentei fazer uma classe que resolveria seu problema usando leitura de fluxo assíncrona, levando em consideração Mark Byers, Rob, stevejay respostas. Ao fazer isso, percebi que há um erro relacionado à leitura do fluxo de saída do processo assíncrono.
Você não pode fazer isso:
Você receberá System. InvalidOperationException: StandardOut não foi redirecionado ou o processo ainda não foi iniciado.
Então você precisa iniciar a leitura assíncrona após o processo ser iniciado:
Fazendo isso, faça uma condição de corrida porque o fluxo de saída pode receber dados antes de defini-los como assíncronos:
Então, algumas pessoas podem dizer que você só precisa ler o fluxo antes de defini-lo como assíncrono. Mas o mesmo problema ocorre. Haverá uma condição de corrida entre a leitura síncrona e o fluxo em modo assíncrono.
Não há como obter uma leitura assíncrona segura de um fluxo de saída de um processo na maneira real como "Process" e "ProcessStartInfo" foram projetados.
Provavelmente, é melhor usar a leitura assíncrona, como sugerido por outros usuários para o seu caso. Mas você deve estar ciente de que pode perder alguma informação devido à condição de corrida.
Nenhuma das respostas acima está fazendo o trabalho.
A solução Rob trava e a solução 'Mark Byers' obtém a exceção descartada (tentei as "soluções" das outras respostas).
Então decidi sugerir outra solução:
Este código depurado e funciona perfeitamente.
Introdução.
A resposta aceita atualmente não funciona (gera exceção) e há muitas soluções alternativas, mas nenhum código completo. Isto é, obviamente, desperdiçando muito tempo das pessoas, porque esta é uma questão popular.
Combinando a resposta de Mark Byers e a resposta de Karol Tyl, escrevi o código completo com base em como eu quero usar o método Process. Start.
Eu usei-o para criar um diálogo de progresso em torno dos comandos do git. É assim que eu usei:
Em teoria, você também pode combinar stdout e stderr, mas eu não testei isso.
As outras soluções (incluindo EM0s) ainda estão em deadlock para meu aplicativo, devido a tempos limite internos e ao uso de StandardOutput e StandardError pelo aplicativo gerado. Aqui está o que funcionou para mim:
Editar: adicionada inicialização do StartInfo ao exemplo de código.
Este post talvez desatualizado, mas eu descobri a causa principal porque normalmente travar é devido ao estouro de pilha para a saída redirectStandard ou se você tiver redirectStandarderror.
Como os dados de saída ou os dados de erro são grandes, isso causará um tempo de interrupção, pois ainda está sendo processado por duração indefinida.
então, para resolver esse problema:
Eu acho que essa é uma abordagem simples e melhor (não precisamos do AutoResetEvent):
Eu estava tendo o mesmo problema, mas o motivo era diferente. No entanto, isso aconteceria no Windows 8, mas não no Windows 7. A linha a seguir parece ter causado o problema.
A solução foi NÃO desabilitar o UseShellExecute. Eu agora recebi uma janela popup do Shell, que é indesejada, mas muito melhor do que o programa esperando que nada de especial aconteça. Então eu adicionei a seguinte solução para isso:
Agora, a única coisa que me incomoda é por que isso está acontecendo no Windows 8 em primeiro lugar.
Eu sei que esta é a ceia de idade, mas, depois de ler esta página inteira, nenhuma das soluções estava funcionando para mim, embora eu não tenha tentado Muhammad Rehan como o código foi um pouco difícil de seguir, embora eu acho que ele estava no caminho certo . Quando eu digo que não funcionou isso não é inteiramente verdade, às vezes funcionaria bem, eu acho que é algo a ver com o comprimento da saída antes de uma marca EOF.
De qualquer forma, a solução que funcionou para mim foi usar diferentes threads para ler o StandardOutput e StandardError e escrever as mensagens.
Espero que isso ajude alguém, que pensou que isso poderia ser tão difícil!
Depois de ler todos os posts aqui, resolvi a solução consolidada de Marko Avlijaš. No entanto, isso não resolveu todos os meus problemas.
Em nosso ambiente, temos um serviço do Windows que está programado para executar centenas de arquivos. bat. cmd. exe diferentes. etc arquivos que se acumularam ao longo dos anos e foram escritos por muitas pessoas diferentes e em diferentes estilos. Nós não temos controle sobre a escrita dos programas & amp; scripts, somos responsáveis ​​apenas pelo agendamento, execução e geração de relatórios sobre sucesso / falha.
Então eu tentei praticamente todas as sugestões aqui com diferentes níveis de sucesso. A resposta de Marko foi quase perfeita, mas quando executada como um serviço, nem sempre captava stdout. Eu nunca cheguei ao fundo do por que não.

Processo . Método WaitForExit.
A documentação de referência da API tem uma nova casa. Visite o Navegador da API em docs. microsoft para ver a nova experiência.
Define o período de tempo para aguardar a saída do processo associado e bloqueia o thread atual de execução até que o tempo tenha transcorrido ou o processo tenha sido encerrado. Para evitar o bloqueio do segmento atual, use o evento Exited.
Para exemplos de código, consulte as páginas de referência de propriedade StandardError e ExitCode.
Assembly: System (no System. dll)
Instrui o componente Process a aguardar indefinidamente que o processo associado seja encerrado.
Instrui o componente Processo a aguardar o número especificado de milissegundos para o processo associado sair.

Waitforexit c # trava
Eu tenho o seguinte código no meu aplicativo:
System. Diagnostics. Process proc = new System. Diagnostics. Process ();
Uma vez que eu chamo isso através de outro aplicativo, o processo está pendente.
Então eu dei um tempo de 5 segundos e agora funciona bem. Mas preciso encontrar uma maneira melhor de corrigir esse problema, pois esse valor de tempo limite pode depender dos recursos do sistema e da quantidade de aplicativo de entrada que precisa ser processada.
Então, minha pergunta é se estamos criando um processo usando System. Diagnostics, o SO cria um thread separado e o torna como thread principal ou thread de interface do usuário?
Ou está criando um thread CLR que é o mesmo que System. Threading. Thread?
Se usarmos o pool de segmentos para criar um segmento de trabalho, essa seria uma opção melhor?
O pool de threads usa o agendamento do modo de usuário?
Aprecie sua ajuda nisso.
Eu preciso saber sobre isso, porque se System. Diagnostics também cria um segmento de plano de fundo ou segmento de trabalho, não adianta criar um thread separado novamente como não haverá nenhuma alteração no final do dia.
Qual é a diferença entre a implementação acima sobre a criação de um thread de segundo plano?
Você está confuso com tópicos internos e externos ao seu aplicativo. Se você usar WaitForExit no seu thread da interface do usuário. ele bloqueará o thread da interface do usuário, deixando-o sem resposta. Se isso for um problema, crie o novo processo no evento DoWork de um BackgroundWorker. Quando o processo termina, o RunWorkerCompleteEvent será acionado, alertando seu thread da interface do usuário.
Marcado como Resposta Min Zhu Microsoft contingent staff, Moderador segunda-feira, 18 de julho de 2011 3:10.
Todas as respostas.
Esperar por um evento com EnableRaisingEvents = false significa que você está usando o WaitForExit como temporizador. Defina para um valor apropriado.
Esperar por um evento com EnableRaisingEvents = false significa que você está usando o WaitForExit como temporizador. Defina para um valor apropriado.
Eu dei 5000 como o valor e resolvi o problema. Minha preocupação é que funcionará de maneira semelhante sob diferentes recursos do sistema, tamanho do conteúdo de entrada, etc.?
O que acontecerá se o processo associado não sair no final do intervalo?
O Windows não é um sistema operacional em tempo real, portanto, qualquer temporizador dependerá do agendamento do sistema operacional. Supostamente, o System. Timers. Timer é o mais preciso.
& quot; O que acontecerá se o processo associado não sair no final do intervalo? & quot; Você desativou este recurso. Se é isso que você está tentando fazer, habilite-o. Se você não quiser bloquear o encadeamento usado para iniciar o processo, inicie-o a partir de um encadeamento em segundo plano. O BackgxroundWorker seria apropriado para isso.
Eu preciso saber sobre isso, porque se System. Diagnostics também cria um segmento de plano de fundo ou segmento de trabalho, não adianta criar um thread separado novamente como não haverá nenhuma alteração no final do dia.
Qual é a diferença entre a implementação acima sobre a criação de um thread de segundo plano?
Eu preciso saber sobre isso, porque se System. Diagnostics também cria um segmento de plano de fundo ou segmento de trabalho, não adianta criar um thread separado novamente como não haverá nenhuma alteração no final do dia.
Qual é a diferença entre a implementação acima sobre a criação de um thread de segundo plano?
Você está confuso com tópicos internos e externos ao seu aplicativo. Se você usar WaitForExit no seu thread da interface do usuário. ele bloqueará o thread da interface do usuário, deixando-o sem resposta. Se isso for um problema, crie o novo processo no evento DoWork de um BackgroundWorker. Quando o processo termina, o RunWorkerCompleteEvent será acionado, alertando seu thread da interface do usuário.
Marcado como Resposta Min Zhu Microsoft contingent staff, Moderador segunda-feira, 18 de julho de 2011 3:10.
A Microsoft está realizando uma pesquisa online para entender sua opinião sobre o site da MSDN. Se você optar por participar, a pesquisa on-line será apresentada quando você sair do site do Msdn.

Waitforexit c # trava
Eu olhei em tópicos diferentes sobre isso, mas todos eles usam o Process. RedirectStandardOutput = True, o que eu não faço.
Estou tentando abrir um processo (aplicativo de console, não feito por mim) para fazê-lo compilar um arquivo. acs especial para um arquivo. o. A estrutura é simples, o único argumento é o arquivo que você deseja compilar.
Mas em determinados arquivos meu aplicativo trava ao tentar abrir o processo. Aqui está meu código:
Para iniciar o processo eu uso praticamente o mesmo código que outro cara fez em C #. E o código dele está funcionando perfeitamente.
Espero que seu dia tenha sido melhor do que ontem, mas que seja pior do que amanhã.
Por favor, marque como resposta se eu resolvi o seu problema. :)
Editado por Visual Vincent sábado, 3 de janeiro de 2015 14:57.
Você já comparou os FileNames e Arguments dos que funcionam e os que não funcionam? Existe alguma diferença neles, como os que trabalham não contêm espaços em branco no nome do arquivo ou argumentos e aqueles que trabalham não contêm espaços em branco neles? Se você acha que esse é o problema, então você precisa adicionar Quotes ao início e ao fim do FileName ou Arguments.
Meu primeiro palpite é que o Arguments precisa das Quotes assim porque, eu vejo espaços em branco no seu exemplo dos Argumentos.
Se você disser que não pode ser feito, então eu vou tentar.
Editado por IronRazerz sábado, 3 de janeiro de 2015 15:51 Marcada com uma resposta por Visual Vincent sábado, 3 de janeiro de 2015 16:33.
Todas as respostas.
Você já comparou os FileNames e Arguments dos que funcionam e os que não funcionam? Existe alguma diferença neles, como os que trabalham não contêm espaços em branco no nome do arquivo ou argumentos e aqueles que trabalham não contêm espaços em branco neles? Se você acha que esse é o problema, então você precisa adicionar Quotes ao início e ao fim do FileName ou Arguments.
Meu primeiro palpite é que o Arguments precisa das Quotes assim porque, eu vejo espaços em branco no seu exemplo dos Argumentos.
Se você disser que não pode ser feito, então eu vou tentar.
Editado por IronRazerz sábado, 3 de janeiro de 2015 15:51 Marcada com uma resposta por Visual Vincent sábado, 3 de janeiro de 2015 16:33.
Você tentou o mesmo comando manualmente em uma janela do console? Talvez pare e espere por algo. Ou não defina CreateNoWindow, ErrorDialog e WIndowStyle e veja o que acontece.
Editado por Viorel_ MVP sábado, 3 de janeiro de 2015 16:27.
Você já comparou os FileNames e Arguments dos que funcionam e os que não funcionam? Existe alguma diferença neles, como os que trabalham não contêm espaços em branco no nome do arquivo ou argumentos e aqueles que trabalham não contêm espaços em branco neles? Se você acha que esse é o problema, então você precisa adicionar Quotes ao início e ao fim do FileName ou Arguments.
Meu primeiro palpite é que o Arguments precisa das Quotes assim porque, eu vejo espaços em branco no seu exemplo dos Argumentos.
Se você disser que não pode ser feito, então eu vou tentar.
Isso realmente fez isso. Eu tinha esquecido que espaços em branco faz com que seja um novo argumento, bobagem comigo. Eu não uso argumentos de processo com frequência. ;)
Espero que seu dia tenha sido melhor do que ontem, mas que seja pior do que amanhã.
Por favor, marque como resposta se eu resolvi o seu problema. :)
Editado por Visual Vincent sábado, 3 de janeiro de 2015 16:33.
Você tentou o mesmo comando manualmente em uma janela do console? Talvez pare e espere por algo. Ou não defina CreateNoWindow, ErrorDialog e WIndowStyle e veja o que acontece.
Fazê-lo da maneira normal (arrastar e soltar, ou fazê-lo via CMD) funciona, sim.
Espero que seu dia tenha sido melhor do que ontem, mas que seja pior do que amanhã.
Por favor, marque como resposta se eu resolvi seu problema. :)
Se você disser que não pode ser feito, então eu vou tentar.
Editado por IronRazerz sábado, 3 de janeiro de 2015 16:39.
A Microsoft está realizando uma pesquisa online para entender sua opinião sobre o site da MSDN. Se você optar por participar, a pesquisa on-line será apresentada quando você sair do site do Msdn.

Комментариев нет:

Отправить комментарий