Processo espera por favor c # tempo limite
Processo waitforexit c # timeout
Obter através da App Store Leia esta publicação em nosso aplicativo!
Process. WaitForExit (Int32)
Agora estou trabalhando em um aplicativo Console Runner que possui o seguinte código para exibir o log e esperar até que o processo seja concluído:
Eu tenho duas perguntas sobre esse pedaço de código.
Percebi que se o processo demorar mais de 30 segundos, a chamada p. ExitCode bombardeia. O que acontece se o meu processo demorar apenas 1 segundo, aguardará 30 segundos de qualquer forma ou o processo será avisado pelo CLR?
Se você tentar obter o ExitCode antes do processo ter saído, a tentativa lança uma exceção. Examine primeiro o recurso HasExited para verificar se o processo associado foi encerrado.
Não há garantia de que, quando sua chamada para WaitForExit retornar, o processo será encerrado. Da documentação de WaitForExit:
A sobrecarga WaitForExit (Int32) é usada para fazer o thread atual aguardar até o processo associado terminar. Essa sobrecarga instrui o componente Processo a aguardar uma quantidade limitada de tempo para que o processo saia. Se o processo associado não sair pelo final do intervalo porque a solicitação de término é negada, o falso é retornado ao procedimento de chamada. Você pode especificar um número negativo (Infinito) por milissegundos e Process. WaitForExit (Int32) se comportará da mesma maneira que a sobrecarga WaitForExit (). Se você passar 0 (zero) para o método, ele retorna verdadeiro somente se o processo já foi encerrado; Caso contrário, ele retorna imediatamente falso.
Observe que isso responde sua segunda pergunta. Se o processo for encerrado antes do tempo decorrido, o WaitForExit retornará.
Como você especificou um tempo limite finito, você permite a possibilidade de a função retornar antes do processo ter terminado. Então, você poderia escrever seu código como este:
George Birbilis @zoomicon.
Engenheiro de informática, Microsoft MVP J # & # 8211; R & amp; D 2004-2018, Borland Spirit of Delphi 2001.
Gotchas at Wait para um aplicativo descascado terminar (com / sem tempo limite) com.
Encontrei um exemplo útil do suporte da Microsoft chamado "Como aguardar a conclusão de um aplicativo descascado usando Visual Basic 2005 ou Visual Basic" em support. microsoft/kb/305368.
No entanto, note que existem várias gotchas com o código fornecido lá (apenas informou a Microsoft sobre isso, espero que eles tomem nota). Também o artigo aponta para as versões C # e C ++ da amostra que, obviamente, precisam das mesmas correções.
1) existe um problema tanto na primeira amostra (espere indefinidamente) como no segundo (espera com tempo limite)
& # 8216; Aguarde a janela de processo para concluir o carregamento.
& # 8216; Aguarde até que o processo saia.
Por que esperar pela entrada ocioso em primeiro lugar? O processo pode nunca entrar no estado ocioso e sair antes disso. De acordo com msdn. microsoft/en-us/library/8d7363e2(v=VS.90).aspx, você pode obter exceção de WaitForInputIdle:
Ocorreu um erro desconhecido. O processo não conseguiu entrar no estado ocioso.
O processo já foi encerrado.
Nenhum processo está associado a este objeto Processo.
Suponho que seja melhor evitar chamar WaitForInputIdle, pois você apenas se importa com WaitForExit lá.
2) Mesmo WaitForExit pode lançar exceções que o código deve verificar de acordo com msdn. microsoft/en-us/library/fb4aw7b8.aspx.
Não existe nenhum processo associado a este objeto Processo.
Você está tentando chamar WaitForExit para um processo que está sendo executado em um computador remoto. Este método está disponível somente para processos que estão sendo executados no computador local.
3) O artigo de suporte não menciona o documento WaitForExit (timeout) (msdn. microsoft/en-us/library/fb4aw7b8.aspx) sobre o tempo limite "infinito":
No Framework versão 3.5 e versões anteriores, a sobrecarga WaitForExit aguardava milissegundos MaxValue (aproximadamente 24 dias), não indefinidamente. Além disso, as versões anteriores não esperaram que os manipuladores de eventos saíssem se o tempo MaxValue completo fosse atingido.
Além disso, parece que a documentação para "WaitForExit (timeout)" não menciona que existe uma constante Timeout. Infinite que tem o valor -1 a usar para tais tempos limite infinitos (encontrado a partir do documento de Thread. Join): msdn. microsoft/ en-us / library / system. threading. timeout. infinite (v = VS.90).aspx.
4) A amostra não consegue chamar Close e, portanto, continua a gastar recursos para controlar o rastreamento (e "bloquear" aqueles identificadores de identificadores, obviamente, embora não seja tão fácil quanto em CPUs antigas e versões do sistema operacional ficar sem alças, espero).
Quando um processo associado sai (ou seja, quando é desligado pelo sistema de operação através de um término normal ou anormal), o sistema armazena informações administrativas sobre o processo e retorna ao componente que chamou WaitForExit. O componente Processo pode acessar a informação, que inclui o ExitTime, usando o Handle para o processo encerrado.
Como o processo associado saiu, a propriedade Handle do componente já não aponta para um recurso de processo existente. Em vez disso, o identificador pode ser usado apenas para acessar a informação do sistema operacional n. ° 8217 sobre o recurso do processo. O sistema está ciente de manipulações para processos que não foram lançados pelos componentes do Processo, portanto, mantém as informações ExitTime e Handle na memória até que o componente Processo liberte especificamente os recursos. Por esse motivo, sempre que você ligar para uma instância do Start for Process, chame Close quando o processo associado for encerrado e você não precisa mais de informações administrativas sobre isso. Fechar libera a memória alocada para o processo encerrado.
Observe também que poderia ter uma cláusula "Usando" ao definir o novo objeto de processo (em vez de Dim) em vez de obrigar explicitamente a "Processar fechar" no final para liberar recursos, conforme observado em msdn. microsoft/en - us / library / system. diagnostics. process. close (v = VS.90).aspx.
O método Fechar faz com que o processo pare de aguardar a saída se ele estivesse esperando, fecha o identificador do processo e limpa as propriedades específicas do processo. Fechar não fecha os leitores e escritores padrão de saída, entrada e erro caso estejam sendo referenciados externamente.
O método Dispose (Boolean) chama Close. Colocar o objeto Processo em um bloco de uso dispõe de recursos sem a necessidade de chamar Close.
5) Outro problema está na 2ª amostra (aguarde com tempo limite). Não menciona ter que chamar WaitForExit () novamente sem params após o WaitForExit (timeout) no caso em que a saída padrão foi redirecionada para manipuladores de eventos assíncronos (deve mencionar este caso para completude)
Quando a saída padrão foi redirecionada para manipuladores de eventos assíncronos, é possível que o processamento de saída não seja concluído quando esse método retornar. Para garantir que o tratamento de eventos assíncrono tenha sido concluído, chame a sobrecarga WaitForExit que não leva nenhum parâmetro depois de receber uma verdade dessa sobrecarga. Para ajudar a garantir que o evento Exited seja tratado corretamente nas aplicações Windows Forms, defina a propriedade SynchronizingObject.
Exemplo de uso.
Resolvi assim:
Eu redirecionava a entrada, a saída e o erro e administrai a leitura dos fluxos de saída e erro. Esta solução funciona para o SDK 7- 8.1, tanto para o Windows 7 como para o Windows 8.
Eu tentei fazer uma aula que resolva seu problema usando a leitura de fluxo assíncrono, levando em conta Mark Byers, Rob, Stevejay responde. Ao fazê-lo, percebi que existe um erro relacionado à leitura assíncrona do fluxo de saída do processo.
Você não pode fazer isso:
Você receberá System. InvalidOperationException: StandardOut não foi redirecionado ou o processo ainda não começou.
Então, você deve iniciar a saída assíncrona lida 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 configurá-lo como assíncrono:
Então algumas pessoas podem dizer que você só precisa ler o fluxo antes de configurá-lo como assíncrono. Mas o mesmo problema ocorre. Haverá uma condição de corrida entre a leitura síncrona e configurará o fluxo em modo assíncrono.
Não há como conseguir uma leitura assíncrona segura de um fluxo de saída de um processo na forma real "Processo" e "ProcessStartInfo" foi projetado.
Você provavelmente está melhor usando a leitura assíncrona, como sugerido por outros usuários para o seu caso. Mas você deve estar ciente de que você pode perder algumas informações 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 descarta. (Eu tentei as "soluções" das outras respostas).
Então eu decidi sugerir outra solução:
Este código é depurado e funciona perfeitamente.
Eu acho que isso é uma abordagem simples e melhor (não precisamos do AutoResetEvent):
Eu estava tendo o mesmo problema, mas a razão era diferente. No entanto, isso 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. Agora recebi uma janela popup do Shell, que é indesejável, mas muito melhor do que o programa esperando que nada de particular aconteça. Então eu adicionei o seguinte trabalho para isso:
Agora, o único problema que me incomoda é o porquê isso está acontecendo no Windows 8, em primeiro lugar.
Introdução.
A resposta atualmente aceita não funciona (lança exceção) e há muitas soluções alternativas, mas nenhum código completo. Isso é, 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 um código completo baseado em como eu quero usar o método Process. Start.
Eu usei-o para criar um diálogo de progresso em torno dos comandos git. É assim que eu usei isso:
Em teoria, você também pode combinar stdout e stderr, mas não testei isso.
Eu sei que isso é velho, mas, depois de ler toda essa página, nenhuma das soluções estava funcionando para mim, embora eu não tentei Muhammad Rehan porque o código era 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, acho que é algo a ver com a duração da saída antes de uma marca EOF.
De qualquer forma, a solução que funcionou para mim era 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!
As outras soluções (incluindo o EM0) ainda estão bloqueadas para o meu aplicativo, devido a tempos de espera internos e ao uso de StandardOutput e StandardError pela aplicação gerada. Aqui está o que funcionou para mim:
Editar: inicialização adicionada de StartInfo para codificar a amostra.
Este post talvez esteja desactualizado, mas descobri a principal causa por que normalmente ele trava é devido ao excesso de pilha para o redirectStandardoutput ou se você tem redirectStandarderror.
Como os dados de saída ou os dados de erro são grandes, isso causará um tempo de espera, pois ele ainda está processando por tempo indefinido.
Processo . Método WaitForExit (Int32)
A documentação de referência da API tem uma nova casa. Visite o navegador da API no docs. microsoft para ver a nova experiência.
Instrui o componente Processo a aguardar o número especificado de milissegundos para que o processo associado saia.
Assembly: System (no System. dll)
Parâmetros.
A quantidade de tempo, em milissegundos, para aguardar o encerramento do processo associado. O máximo é o maior valor possível de um inteiro de 32 bits, que representa infinito para o sistema operacional.
Valor de retorno.
é verdade se o processo associado tenha saído; caso contrário, falso.
A configuração de espera não pôde ser acessada.
Nenhum Id do processo foi configurado e um identificador do qual a propriedade Id pode ser determinada não existe.
Não existe nenhum processo associado a este objeto Processo.
Você está tentando chamar WaitForExit (Int32) para um processo que está sendo executado em um computador remoto. Este método está disponível somente para processos que estão sendo executados no computador local.
WaitForExit (Int32) faz o thread atual aguardar até o processo associado terminar. Ele deve ser chamado após todos os outros métodos serem chamados no processo. Para evitar o bloqueio do segmento atual, use o evento Exitado.
Esse método instrui o componente Processo a aguardar um período finito de tempo para o processo sair. Se o processo associado não sair pelo final do intervalo porque a solicitação de término é negada, o falso é retornado ao procedimento de chamada. Você pode especificar um número negativo (Infinito) por milissegundos e Processar. WaitForExit (Int32) irá comportar-se da mesma forma que a sobrecarga WaitForExit (). Se você passar 0 (zero) para o método, ele retorna verdadeiro somente se o processo já foi encerrado; Caso contrário, ele retorna imediatamente falso.
No Quadro 3.5 e versões anteriores, se o milissegundo fosse -1, a sobrecarga WaitForExit (Int32) esperava milissegundos MaxValue (aproximadamente 24 dias), não indefinidamente.
Quando a saída padrão foi redirecionada para manipuladores de eventos assíncronos, é possível que o processamento de saída não seja concluído quando esse método retornar. Para garantir que o tratamento de eventos assíncrono tenha sido concluído, chame a sobrecarga WaitForExit () que não leva nenhum parâmetro depois de receber uma verdade dessa sobrecarga. Para ajudar a garantir que o evento Exited seja tratado corretamente nas aplicações Windows Forms, defina a propriedade SynchronizingObject.
Quando um processo associado é encerrado (é encerrado pelo sistema operacional através de uma terminação normal ou anormal), o sistema armazena informações administrativas sobre o processo e retorna ao componente que chamou WaitForExit (Int32). O componente Processo pode acessar a informação, que inclui o ExitTime, usando o Handle para o processo encerrado.
Como o processo associado saiu, a propriedade Handle do componente já não aponta para um recurso de processo existente. Em vez disso, o identificador pode ser usado apenas para acessar as informações do sistema operacional sobre o recurso do processo. O sistema está ciente de manipulações para processos que não foram lançados pelos componentes do Processo, portanto, mantém as informações ExitTime e Handle na memória até que o componente Processo liberte especificamente os recursos. Por esse motivo, sempre que você ligar para uma instância do Start for Process, chame Close quando o processo associado for encerrado e você não precisa mais de informações administrativas sobre isso. Fechar libera a memória alocada para o processo encerrado.
Consulte o exemplo de código para a propriedade ExitCode.
para uma confiança total para o chamador imediato. Este membro não pode ser usado por código parcialmente confiável.
Code Ducky.
um blog para codificadores por codificadores.
Trabalhando com processos em.
Os idiomas de scripts e shell são geralmente construídos em torno da capacidade de um processo para iniciar facilmente e trabalhar com os resultados dos outros. Este é o principal modo de processamento em bash, enquanto o ruby suporta pelo menos 5 abordagens integradas com diferentes níveis de flexibilidade e concisão.
Em, isso é uma espécie de operação normalmente é feito através da API System. Diagnostics. Process. O Process API é bastante geral e poderoso, mas pode ser complicado e difícil de usar corretamente nos casos de uso comum que são tratados tão bem pelas linguagens acima. Como um spoiler, acabei envolvendo grande parte dessa complexidade em uma nova biblioteca: MedallionShell. Com o MedallionShell, esse tipo de tarefa é um one-liner:
Mais sobre isso mais tarde, no entanto. Por enquanto, vamos voltar ao Processo. Como um exemplo concreto, recentemente queria que meu aplicativo lancasse uma instância do NodeJS para executar o compilador menos css. Eu precisava escrever na entrada padrão do Node & # 8217; ao capturar o texto de saída padrão, texto de erro padrão e código de saída.
Uma tentativa inicial.
Aqui é o código com que comecei:
Este código é bastante detalhado; infelizmente também é bastante buggy.
Lidando com os argumentos do processo.
Um dos primeiros problemas que notamos com este código é que a propriedade Arguments no ProcessStartInfo é apenas uma string. Se os argumentos que estamos passando são dinâmicos, precisaremos fornecer a lógica de escape adequada antes de concatenar para impedir que coisas como espaços em caminhos de arquivos sejam quebrados. Escapar os argumentos da linha de comando do Windows é estranhamente complexo; Felizmente, o código necessário para implementá-lo está bem documentado nesta publicação do StackOverflow. Assim, a primeira mudança que nós vamos fazer é adicionar lógica de escape:
Lidar com deadlocks.
Um problema menos óbvio é o bloqueio. Os três fluxos de processo (entrada, saída e erro) são finitos em quanto de conteúdo eles podem armazenar. Se o buffer interno for preenchido, então quem estiver escrevendo para o fluxo irá bloquear. Neste código, por exemplo, não lemos os fluxos de saída e erro até que o processo tenha saído. Isso significa que podemos encontrar-nos em um caso em que o Node esgota o buffer de erro. Nesse caso, o Nó bloquearia a gravação em erro padrão, enquanto nosso aplicativo está bloqueado a leitura até o final do padrão. Assim, nós nos encontramos em um impasse!
O Process API fornece um método que parece projetado para lidar com isso: BeginOutput / ErrorReadLine. Com este método, você pode assinar o assíncrono & # 8220; DataReceived & # 8221; eventos em vez de ler os fluxos de saída diretamente. Dessa forma, você pode ouvir ambos os fluxos ao mesmo tempo. Infelizmente, este método não fornece nenhuma maneira de saber quando o último bit de dados foi recebido. Porque tudo é assíncrono, é possível (e eu observei isso) para que os eventos disparem depois que WaitForExit () retornou.
Felizmente, podemos fornecer nossa própria solução alternativa usando Tarefas para ler asíncronamente as transmissões enquanto aguardamos o Nó para sair:
Adicionando um tempo limite.
Outra questão que gostaria de lidar é a de um processo pendurado. Em vez de esperar para que o processo saia, nosso código seria mais robusto se forçássemos um timeout em vez disso:
Async todo o caminho!
Enquanto nós agora estamos usando o IO assíncrono para ler dos fluxos do processo, ainda estamos bloqueando um segmento enquanto aguardamos o processo para concluir. Podemos melhorar a eficiência aqui, indo totalmente assíncrono:
Adaptando-se a volumes de dados maiores.
Outra questão que pode surgir ao tentar generalizar essa abordagem é a do volume de dados. Se estivermos fornecendo uma grande quantidade de dados através do processo, nós provavelmente queremos substituir as chamadas convenientes ReadToEndAsync () com loops de leitura assíncronos que processam cada pedaço de dados conforme ele vem.
Mudando para MedallionShell.
Nós já construímos um código (esperançosamente) correto, robusto e eficiente para trabalhar com um processo. No entanto, espero que este exemplo o tenha convencido de que a API do Processo não é suficiente para o trabalho quando se trata de facilidade de uso. Para esse fim, irei apresentar uma alternativa: a biblioteca MedallionShell (disponível no NuGet). Aqui, a lógica equivalente usando MedallionShell:
Com o MedallionShell, os argumentos são escapados automaticamente, os fluxos de processo são automaticamente armazenados em buffer para evitar o impasse, e tudo está bem envolvido em uma API baseada em tarefas compatível com asínc. Nós não teremos que nos preocupar em chamar Dispose (): por padrão, o Processo é descartado automaticamente após a conclusão do comando.
O MedallionShell também oferece sobrecargas do operador para permitir o redirecionamento semelhante à da entrada padrão e saída padrão. Isso significa que você pode usar & # 8220; & lt; & # 8221; e & # 8220;> & # 8221; para canalizar dados de e para fluxos, arquivos e coleções. Você pode até usar o & # 8220; | & # 8221; para canalizar dados de um objeto Command para outro.
Mike Adelson.
Últimas publicações de Mike Adelson (ver todos)
Implementando Equals () e GetHashCode () em C # 7 - 3 de junho de 2017 Scripting in C # - 3 de maio de 2017 7 maneiras de usar C # 7 throw expressions - 26 de abril de 2017.
Sobre Mike Adelson.
I & # 8217; m engenheiro de software em Applied Predictive Technologies em Washington D. C., onde trabalho em & # 8220; dados grandes & # 8221; análise e desenvolvimento web. No meu tempo livre, eu gosto de ler, trabalhar em vários projetos paralelos e responder perguntas no StackOverflow.
Pós-navegação.
7 pensamentos sobre & ldquo; Trabalhando com processos em & rdquo;
É possível ler e escrever para o mesmo processo dentro do mesmo programa. Eu usei o shell medalhão para ler a saída de um programa de console interativo. Mas quando eu iniciar um segmento diferente para escrever comandos para o programa, o writestream. writeline parece apenas pendurar. Estou tentando controlar pianobar (veja github). Há algum passo ao tentar ler uma linha do processo e responder com uma linha. Isto está me enlouquecendo.
Sim, deve ser possível ler e escrever para um processo dentro do mesmo programa. Certifique-se de que está usando a versão mais recente do MedallionShell e que a entrada padrão do comando está definida como AutoFlush (deve ser o padrão).
Você pode observar WriteLine para pendurar se o processo de destino não for puxar os dados e o buffer interprocesso for preenchido (evitando assim que o preenchimento seja concluído).
É difícil para mim dizer mais sem ver o seu código; considere postar uma descrição mais detalhada e uma amostra de código como um problema em https: // github / madelson / MedallionShell.
Obrigado Michael. Eu fiz exatamente isso, o problema # 9 #. Liguei a minha pergunta. Claramente, eu estava com muito sono para escrever qualquer coisa. Eu quis dizer que há algum passo que é necessário que eu esteja faltando. Algo óbvio para todos os outros por mim.
É possível aguardar uma string específica no fluxo de saída do comando?
bool found = await cmd. StandardOutput. Expect (searchstring, timeout);
Não há funcionalidades incorporadas para fazer isso. Se a string não abranger uma linha, você poderia fazer:
enquanto ((linha = cmd. StandardOutput. ReadLine ())! = null)
Se a cadeia de pesquisa abranger várias linhas, você pode usar uma técnica de loop semelhante, onde você acompanha os últimos N caracteres onde N é o comprimento da seqüência de pesquisa.
Комментарии
Отправить комментарий