Saída padrão waitforexit do processo
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:
Saída padrão waitforexit do processo
Quando você cria seu objeto Process, defina StartInfo apropriadamente:
então inicie o processo e leia:
Você pode usar int. Parse () ou int. TryParse () para converter as cadeias em valores numéricos. Você pode ter que fazer alguma manipulação de seqüência de caracteres primeiro se houver caracteres numéricos inválidos nas seqüências de caracteres que você lê.
Você pode processar sua saída de forma síncrona ou assíncrona.
Observe que é melhor processar a saída e os erros: eles devem ser tratados separadamente.
(*) Para alguns comandos (aqui StartInfo. Arguments) você deve adicionar a diretiva / c, caso contrário, o processo congela no WaitForExit ().
Se você não precisa complicar as operações com a saída, você pode ignorar o método OutputHandler, apenas adicionando os manipuladores diretamente em linha:
A maneira padrão de fazer isso é ler o fluxo StandardOutput do Processo. Há um exemplo nos documentos do MSDN vinculados. Semelhante, você pode ler a partir do StandardError e gravar em StandardInput.
Tudo bem, para qualquer um que deseje leitura de Erros e Saídas, mas receba deadlocks com qualquer uma das soluções, fornecidas em outras respostas (como eu), aqui está uma solução que construí depois de ler a explicação do MSDN para a propriedade StandardOutput.
A resposta é baseada no código do T30:
você pode usar a memória compartilhada para os 2 processos para se comunicar, confira MemoryMappedFile.
você criará principalmente um arquivo de memória mapeado mmf no processo pai usando a instrução "using" e então criará o segundo processo até que ele termine e deixe gravar o resultado para o mmf usando BinaryWriter, então leia o resultado do mmf usando o processo pai , você também pode passar o nome mmf usando argumentos de linha de comando ou codificar isso.
Verifique se, ao usar o arquivo mapeado no processo pai, você faz o processo filho gravar o resultado no arquivo mapeado antes que o arquivo mapeado seja liberado no processo pai.
Exemplo: processo pai.
Para usar este exemplo, você precisará criar uma solução com dois projetos dentro, então você pega o resultado de compilação do processo filho de% childDir% / bin / debug e copia para% parentDirectory% / bin / debug, em seguida, executa o projeto pai.
childDir e parentDirectory são os nomes das pastas dos seus projetos no pc boa sorte :)
VBlog do Lucian VBlog Lucian.
Às vezes, você quer iniciar um utilitário externo e enviar entrada para ele e também capturar sua saída. Mas é fácil entrar em um impasse desse jeito.
Usando p como novo System. Diagnostics. Process.
p. StandardInput. Write ("world" & amp; vbCrLf & amp; "hello")
'deadlock aqui se p precisa escrever mais de 12k para StandardOutput.
Dim op = p. StandardOutput. ReadToEnd ()
Console. WriteLine ("OUTPUT:"): Console. WriteLine (op)
O impasse neste caso surge porque "cat" (um utilitário unix padrão) primeiro lê a partir de StandardInput, em seguida, escreve para StandardOutput, em seguida, lê novamente, e assim por diante, até que não haja mais nada para ler. Mas se o seu StandardOutput enche ninguém para lê-lo, então ele não pode mais escrever e bloquear.
O número "12k" é arbitrário e eu não confiaria nele.
Usando p como novo System. Diagnostics. Process.
'deadlock aqui se p precisa escrever mais de 12k para StandardError.
Dim op = p. StandardOutput. ReadToEnd ()
Dim err = p. StandardError. ReadToEnd ()
Console. WriteLine ("OUTPUT:"): Console. WriteLine (op)
Console. WriteLine ("ERROR:"): Console. WriteLine (err)
A documentação do MSDN diz, "Você pode usar operações de leitura assíncronas para evitar essas dependências e seu potencial de deadlock. Como alternativa, você pode evitar a condição de deadlock criando dois threads e lendo a saída de cada fluxo em um thread separado." 'Eu vou fazer.
Usando encadeamentos para redirecionar sem deadlock.
'BOM CÓDIGO: isso não será um impasse.
Usando p como novo diagnóstico. Processo.
'não WaitForExit ainda desde que introduziria deadlocks.
p. InputAndOutputToEnd ("world" & amp; vbCrLf & amp; "hello", op, Nothing)
Console. WriteLine ("OUTPUT:"): Console. WriteLine (op)
'' 'InputAndOutputToEnd: uma maneira prática de usar entrada / saída / erro redirecionado em uma p.
'' '& lt; nome do parametro = "p" & gt; O p para redirecionar. Tem de ter UseShellExecute definido como falso. & Lt; / param & gt;
'' '& lt; param name = "StandardInput" & gt; Esta string será enviada como entrada para a p. (deve ser Nothing, se não for StartInfo. RedirectStandardInput) & lt; / param & gt;
'' '& lt; param name = "StandardOutput" & gt; A saída de p será coletada nesta string ByRef. (deve ser Nothing se não for StartInfo. RedirectStandardOutput) & lt; / param & gt;
'' '& lt; nome do parametro = "StandardError" & gt; O erro do p será coletado nesta string ByRef. (deve ser Nothing se não for StartInfo. RedirectStandardError) & lt; / param & gt;
'' '& lt; remarks & gt; Esta função resolve o problema de deadlock mencionado em msdn. microsoft/pt-br/library/system. diagnostics. p.standardoutput. aspx</remarks>
& lt; RuntimepilerServices. Extension () & gt; Sub InputAndOutputToEnd (ByVal p Como Diagnostics. Process, ByVal StandardInput como String, ByRef StandardOutput como String, ByRef StandardError como String)
Se p não é nada, em seguida, lança novo ArgumentException ("p deve ser não-nulo")
'Suponha que p começou. Infelizmente não há como checar.
Se p. StartInfo. UseShellExecute Em seguida, lançar novo ArgumentException ("Set StartInfo. UseShellExecute to false")
If (p. StartInfo. RedirectStandardInput & lt; (gt; StandardInput IsNot Nothing)) Em seguida, lançar novo ArgumentException ("Fornecer uma entrada não nula somente quando StartInfo. RedirectStandardInput")
If (p. StartInfo. RedirectStandardOutput & lt; (StandardOutput IsNot Nothing)) Em seguida, lançar novo ArgumentException ("Fornecer uma saída não nula somente quando StartInfo. RedirectStandardOutput")
If (p. StartInfo. RedirectStandardError & lt; (gt; StandardError IsNot Nothing)) Em seguida, lançar novo ArgumentException ("Fornecer um erro não nulo somente quando StartInfo. RedirectStandardError")
Dim outputData As New InputAndOutputToEndData.
Dim errorData As New InputAndOutputToEndData.
Se p. StartInfo. RedirectStandardOutput Então.
outputData. Thread = Novo Threading. Thread (AddressOf InputAndOutputToEndProc)
Se p. StartInfo. RedirectStandardError Então.
errorData. Thread = Novo Threading. Thread (AddressOf InputAndOutputToEndProc)
Se p. StartInfo. RedirectStandardInput Então.
If p. StartInfo. RedirectStandardOutput Then outputData. Thread. Join (): StandardOutput = outputData. Output.
Se p. StartInfo. RedirectStandardError Então, errorData. Thread. Join (): StandardError = errorData. Output.
Se outputData. Exception IsNot Nothing Então lance outputData. Exception.
If errorData. Exception IsNot Nothing Em seguida, lance errorData. Exception.
Classe privada InputAndOutputToEndData.
Public Thread As Threading. Thread.
Fluxo público como IO. StreamReader.
Saída Pública como String.
Exceção pública como exceção.
Private Sub InputAndOutputToEndProc (ByVal data_ como objeto)
Dim dados = DirectCast (data_, InputAndOutputToEndData)
Tente: data. Output = data. Stream. ReadToEnd: captura e como exceção: data. Exception = e: End Try.
Cancelar resposta.
Por que não usar process. OutputDataReceived e process. ErrorDataReceived?
Dessa forma, você pode ecoar (ou capturar) a saída de ambos na ordem recebida.
Isso parece muito mais simples que async ou threading para mim.
Propriedade Process. StandardOutput.
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.
Obtém um fluxo usado para ler a saída textual do aplicativo.
Assembly: System (no System. dll)
Valor da propriedade.
Um StreamReader que pode ser usado para ler o fluxo de saída padrão do aplicativo.
O fluxo StandardOutput foi aberto para operações de leitura assíncrona com BeginOutputReadLine.
Quando um processo grava texto em seu fluxo padrão, esse texto é normalmente exibido no console. Ao redirecionar o fluxo StandardOutput, você pode manipular ou suprimir a saída de um processo. Por exemplo, você pode filtrar o texto, formatá-lo de maneira diferente ou gravar a saída no console e em um arquivo de log designado.
Para usar o StandardOutput, você deve definir ProcessStartInfo. UseShellExecute como false e deve definir ProcessStartInfo. RedirectStandardOutput como true. Caso contrário, a leitura do fluxo StandardOutput gerará uma exceção.
O fluxo StandardOutput redirecionado pode ser lido de forma síncrona ou assíncrona. Métodos como Read, ReadLine e ReadToEnd executam operações de leitura síncrona no fluxo de saída do processo. Essas operações de leitura síncrona não são concluídas até que o Processo associado grave em seu fluxo StandardOutput ou feche o fluxo.
Por outro lado, BeginOutputReadLine inicia operações de leitura assíncrona no fluxo StandardOutput. Esse método ativa um manipulador de eventos designado para a saída do fluxo e retorna imediatamente ao responsável pela chamada, que pode executar outro trabalho enquanto a saída do fluxo é direcionada para o manipulador de eventos.
As operações de leitura síncrona introduzem uma dependência entre a leitura do responsável pela chamada do fluxo StandardOutput e a gravação do processo filho nesse fluxo. Essas dependências podem resultar em condições de deadlock. Quando o chamador lê o fluxo redirecionado de um processo filho, ele depende do filho. O chamador aguarda na operação de leitura até que o filho grave no fluxo ou feche o fluxo. Quando o processo filho grava dados suficientes para preencher seu fluxo redirecionado, ele depende do pai. O processo filho aguarda na próxima operação de gravação até que o pai leia o fluxo completo ou feche o fluxo. A condição de deadlock resulta quando o chamador e o processo filho aguardam um ao outro para concluir uma operação e nenhum deles pode prosseguir. Você pode evitar deadlocks avaliando dependências entre o chamador e o processo filho.
O seguinte código C #, por exemplo, mostra como ler de um fluxo redirecionado e aguardar a saída do processo filho.
O exemplo de código evita uma condição de deadlock chamando p. StandardOutput. ReadToEnd antes de p. WaitForExit. Uma condição de deadlock pode resultar se o processo pai chama p. WaitForExit antes de p. StandardOutput. ReadToEnd e o processo filho grava texto suficiente para preencher o fluxo redirecionado. O processo pai aguardaria indefinidamente que o processo filho fosse encerrado. O processo filho esperaria indefinidamente que o pai lesse todo o fluxo StandardOutput.
Há um problema semelhante quando você lê todo o texto da saída padrão e dos fluxos de erro padrão. O seguinte código C #, por exemplo, executa uma operação de leitura nos dois fluxos.
O exemplo de código evita a condição de deadlock executando operações de leitura assíncrona no fluxo StandardOutput. Uma condição de deadlock resulta se o processo pai chamar p. StandardOutput. ReadToEnd seguido por p. StandardError. ReadToEnd e o processo filho grava texto suficiente para preencher seu fluxo de erro. O processo pai esperaria indefinidamente que o processo filho fechasse seu fluxo StandardOutput. O processo filho esperaria indefinidamente que o pai lesse o fluxo completo do StandardError.
Você pode usar operações de leitura assíncronas para evitar essas dependências e seu potencial de deadlock. Como alternativa, você pode evitar a condição de deadlock criando dois threads e lendo a saída de cada fluxo em um thread separado.
Você não pode mesclar operações de leitura assíncrona e síncrona em um fluxo redirecionado. Depois que o fluxo redirecionado de um processo é aberto no modo assíncrono ou síncrono, todas as operações de leitura adicionais nesse fluxo devem estar no mesmo modo. Por exemplo, não siga BeginOutputReadLine com uma chamada para ReadLine no fluxo StandardOutput ou vice-versa. No entanto, você pode ler dois fluxos diferentes em modos diferentes. Por exemplo, você pode chamar BeginOutputReadLine e, em seguida, chamar ReadLine para o fluxo StandardError.
Saída padrão waitforexit do processo
Você está executando console & quot; cmd & quot; ?
Se sim, então você tem que digitar exit também.
// Processo finalizado antes do período de tempo limite.
// Imprime mensagem de erro?
Eu gostaria de tentar isso, mas é muito de um hack. Eu tenho muitos comandos diferentes que levam diferentes quantidades de tempo (30 segundos a 25 minutos) para que não haja configuração em tempo real que eu possa colocar sem destruir meu desempenho. Esta função tem funcionado corretamente para vários comandos nos últimos 6 meses e agora ela decide me sacar. Eu tentei em um computador diferente sem problemas (o que realmente está mexendo comigo). Eu sei que não é o redirecionamento de saída / erro porque um novo WINDOW está sendo criado no servidor que estou remoting. Assim que fecho essa janela, meu processo sai como esperado e a saída correta é exibida no lado do usuário.
Obrigado por sua ajuda, mas estou ficando realmente frustrado com esse problema.
Sem conhecer os detalhes da mensagem, estamos apenas adivinhando o problema.
Você já instalou o 3.5 beta ou o Visual Studio 2008 beta?
Como você está usando o processo para iniciar o programa, Process. Start (& quot; file. exe & quot;), ou você está usando ProcessStartInfo?
Não, eu tenho 2003 e 2005 instalado.
proc = new Process ();
procSI = new ProcessStartInfo ();
Eu então configurei um novo thread para o StandardError e o StandardOutput.
Eu então escrevo meus comandos e.
if (redirecionando para fora do padrão)
Iniciar discussão para st. Fora.
Se (redirecionando erro padrão)
Iniciar discussão para st. erro.
Proc. WaitForExit (); & lt; -------- é onde ocorre a janela Relatório de erros do Windows genérico.
Traduzi o que pude da janela que aparece.
Veja também: Microsoft Visual Studio 2005, clique aqui para exibir o artigo traduzido
Porque o problema ocorre, ele termina o Microsoft Visual Studio 2005. Aplicamos a inconveniência, não há desculpa.
Obrigado novamente por todo o seu tempo.
Por que você está fazendo isso? Você não possui esse fluxo, então você não deveria estar fechando.
Isso é um erro de digitação? Antes de você estar falando sobre uma variável chamada "proc", não "Proc". Então, isso é simplesmente uma referência nula porque você está tentando invocar um método em uma referência diferente de & quot; proc & quot ;?
Você não deseja fechar o objeto sIn até que o aplicativo seja encerrado se você estiver redirecionando. Se o aplicativo gravar na saída padrão ou ler na entrada padrão depois de você fechar um deles, isso poderá causar uma exceção.
Você tem o rastreamento de pilha dessa mensagem de erro?
Você não deseja fechar o objeto sIn até que o aplicativo seja encerrado se você estiver redirecionando.
Não se deve fechar nenhum desses fluxos. O objeto Process possui-os e é o responsável pela limpeza após ele mesmo. Deve-se, na melhor das hipóteses, chamar Process. Dispose () depois de terminar com o objeto Process.
Eu criei o StreamWriter sIn antes de criar o objeto Process do processo. Eu então redireciono a entrada após o comando proc. Start (), então como eu não possuo isso? Independentemente disso, eu posso fazer a mudança para mover o sIn. Close () para depois da chamada WaitForExit para ver se isso faz alguma alteração.
O Proc foi um tipo, deveria ter sido proc.
Novamente, não é uma mensagem de erro, portanto, não há rastreamento de pilha. Meu redirecionamento StandardError está vazio e o redirecionamento de saída padrão contém o que eu esperava, mas nada indicando um erro. É por isso que tudo ainda funciona depois de fechar a janela Relatório de erros do Windows.
Vou postar o que acontece depois de mover a linha sIn. Close () abaixo da linha WaitForExit ().
Você não deseja fechar o objeto sIn até que o aplicativo seja encerrado se você estiver redirecionando.
Não se deve fechar nenhum desses fluxos. O objeto Process possui-os e é o responsável pela limpeza após ele mesmo. Deve-se, na melhor das hipóteses, chamar Process. Dispose () depois de terminar com o objeto Process.
Ok, eu estou fazendo Process. Close no bloco finally do meu código, por isso deve ser cuidado então.
Perdoem o meu comentário "não possuírem" o que fiz anteriormente. Acabei de voltar do almoço e estava perdendo o fato de que o processo tem controle sobre isso.
Process. Close é o método recomendado para fechar os fluxos padrão de entrada e saída padrão (e padrão).
Eu ficaria surpreso se o método Dispose não chamasse Close, pelo menos como parte de sua operação. Eu preferiria usar o fato de que, como o Process implementa IDisposable (indiretamente através do Componente de extensão que o implementa), deve-se chamar Dispose e deixar isso para a limpeza apropriada. Eu não recomendaria chamar Process. Close em vez de, nem além de Process. Dispose.
Process. Close é o método recomendado para fechar os fluxos padrão de entrada e saída padrão (e padrão).
Eu ficaria surpreso se o método Dispose não chamasse Close, pelo menos como parte de sua operação. Eu preferiria usar o fato de que, como o Process implementa IDisposable (indiretamente através do Componente de extensão que o implementa), deve-se chamar Dispose e deixar isso para a limpeza apropriada. Eu não recomendaria chamar Process. Close em vez de, nem além de Process. Dispose.
Como eu tenho certeza que você sabe, estes são funcionalmente equivalentes:
using (SomethingDisposable myObject =.)
// use myObject aqui.
// use myObject aqui.
if (myObject! = null) myObject. Dispose ();
Portanto, se a primeira recomendação é usar um bloco de uso, o melhor seria chamar Dispose, não Close, quando, como você disse, você sabe que está pronto com o objeto.
Por apenas chamar Close em algo que implementa IDisposable, o desenvolvedor está potencialmente cometendo um erro. Se Dispose fizer alguma limpeza adicional além de apenas delegar para Close, o programador está se preparando para um bug apenas chamando Close.
Pode haver um caso para chamar Close, mas somente se você não tiver terminado com o objeto, como você indicou na parte inferior da sua última resposta. Mas quando terminar, ligue para Dispose.
Como eu tenho certeza que você sabe, estes são funcionalmente equivalentes:
using (SomethingDisposable myObject =.)
// use myObject aqui.
// use myObject aqui.
if (myObject! = null) myObject. Dispose ();
Portanto, se a primeira recomendação é usar um bloco de uso, o melhor seria chamar Dispose, não Close, quando, como você disse, você sabe que está pronto com o objeto.
Por apenas chamar Close em algo que implementa IDisposable, o desenvolvedor está potencialmente cometendo um erro. Se Dispose fizer alguma limpeza adicional além de apenas delegar para Close, o programador está se preparando para um bug apenas chamando Close.
Pode haver um caso para chamar Close, mas somente se você não tiver terminado com o objeto, como você indicou na parte inferior da sua última resposta. Mas quando terminar, ligue para Dispose.
DisposableClass obj = new DisposableClass ();
ID descartável descartável = obj como IDisposable;
if (descartável! = nulo)
Mas sim, é isso que uma declaração de uso é "funcionalmente equivalente" para; mas eu não concordo explicitamente chamando Dispose na presença de um & quot; Close & quot; O método deve ser a primeira escolha devido à falta de escopo com a chamada Dispose. Por exemplo, o seguinte:
using (Process process = new Process ())
. é um erro de sintaxe.
Enquanto o seguinte:
Process process = new Process ();
// não há como garantir "processar & quot; não vai.
// ser acessado após o acima.
É um erro de tempo de execução (ObjectDisposedException). Usando Close não causa o erro de tempo de execução:
Process process = new Process ();
É sempre melhor trocar um erro em tempo de compilação por um erro em tempo de execução.
Então, eu configurei um ponto de interrupção após a chamada proc. WaitForExit () e ainda não atingi este ponto de interrupção. Então parece que isso é um grande problema.
Então, eu configurei um ponto de interrupção após a chamada proc. WaitForExit () e ainda não atingi este ponto de interrupção. Então parece que isso é um grande problema.
Eu tinha o serviço funcionando, mas eu parei porque ele tinha funcionado por 2 horas e nunca tinha o ponto de interrupção que deveria ter atingido dentro de 10 minutos de mim começando meu cliente. Eu descomentei a linha sIn. Close () agora mesmo e reiniciei o serviço e o Cliente e tudo está funcionando como antes. Eu posso acertar o ponto de interrupção após o WaitForExit () e eu concluir, com a mensagem de relatório de erros do Windows ainda (como era antes).
Então, no meu caso, eu preciso fechar o fluxo de entrada para poder sair do processo como esperado. Existem outras ideias?
Eu posso recomment a linha sIn. Close () se você quiser checar alguma coisa.
Eu tinha o serviço funcionando, mas eu parei porque ele tinha funcionado por 2 horas e nunca tinha o ponto de interrupção que deveria ter atingido dentro de 10 minutos de mim começando meu cliente. Eu descomentei a linha sIn. Close () agora mesmo e reiniciei o serviço e o Cliente e tudo está funcionando como antes. Eu posso acertar o ponto de interrupção após o WaitForExit () e eu concluir, com a mensagem de relatório de erros do Windows ainda (como era antes).
Então, no meu caso, eu preciso fechar o fluxo de entrada para poder sair do processo como esperado. Existem outras ideias?
Eu posso recomment a linha sIn. Close () se você quiser checar alguma coisa.
Como você está usando a entrada padrão e a saída padrão? Você está usando algum método ReadLine?
Peter, meu ponto é:
Se você não chamar Dispose em um objeto que implementa (direta ou indiretamente) IDisposable, então você está apenas pedindo um bug. Eu não quero discutir isso sem parar. Você pode continuar do jeito que você faz, e eu vou ficar com o meu. Contanto que não tenhamos que manter o código um do outro, tudo bem.
E, a propósito, um & quot; usando & quot; bloco não protege você também. Nada impede que você declare a variável fora do bloco (se bem me lembro), então ela ainda pode estar no escopo após o término do bloco. Você tem que ser diligente em escrever o código correto. Se você declarar no campo & quot; using & quot; declaração, isso é um caminho. Mas rejeitar usando a abordagem try / finally apenas porque deixa a variável no escopo não é realmente o ponto. Ainda precisa ser Dispose () em algum lugar.
Eu tinha o serviço funcionando, mas eu parei porque ele tinha funcionado por 2 horas e nunca tinha o ponto de interrupção que deveria ter atingido dentro de 10 minutos de mim começando meu cliente. Eu descomentei a linha sIn. Close () agora mesmo e reiniciei o serviço e o Cliente e tudo está funcionando como antes. Eu posso acertar o ponto de interrupção após o WaitForExit () e eu concluir, com a mensagem de relatório de erros do Windows ainda (como era antes).
Então, no meu caso, eu preciso fechar o fluxo de entrada para poder sair do processo como esperado. Existem outras ideias?
Eu posso recomment a linha sIn. Close () se você quiser checar alguma coisa.
Como você está usando a entrada padrão e a saída padrão? Você está usando algum método ReadLine?
Novamente, isso não é uma exceção que está sendo lançada, por isso não estou vendo detalhes de exceção. Eu não vou diretamente para o bloco catch no meu código, volto DIRETAMENTE após a chamada WaitForExit (). A janela que estou recebendo é a mesma que você recebe quando QUALQUER produto da Microsoft fecha inesperadamente e o MS quer informações sobre o Crash. Então, novamente, não há detalhes de exceção. No entanto, em um dos Logs do sistema, estou recebendo uma mensagem (traduzida do japonês)
& quot; Devenv. exe aplicação erros ocorrem, versão 8.0.50727.762 dos erros ocorridos módulo msvcr80.dll, versão 8.0.50727.762, erros ocorridos endereço 0x00039001.
Para mais informações, visite o site www. microsoft. com/fwlink/events. asp e consulte o Helo and Support Center. & Quot;
Estou redirecionando a entrada Padrão para passar os diferentes comandos porque estava tendo problemas para fazer com que funcionassem como eu queria formar o StartInfo. Estou redirecionando os fluxos de saída e erro para verificar o que eles contêm depois que o processo foi encerrado. Isso permitirá que eu verifique qualquer coisa que eu gostaria em qualquer fluxo, uma vez que tenhamos terminado. Também não permito que nenhum dos threads de redirecionamento de saída ou erro se junte até que o processo tenha passado pela chamada WaitForExit.
Estou completamente perplexo.
Peter, meu ponto é:
Se você não chamar Dispose em um objeto que implementa (direta ou indiretamente) IDisposable, então você está apenas pedindo um bug. Eu não quero discutir isso sem parar. Você pode continuar do jeito que você faz, e eu vou ficar com o meu. Contanto que não tenhamos que manter o código um do outro, tudo bem.
Eu não concordo. Não é um "bug" para não chamar Dispose. Seus recursos não serão liberados imediatamente, mas o GC os liberará se precisar da memória (supondo que o padrão Dispose esteja adequadamente implementado e exista um finalizador). Se a turma que você está usando implementa um & quot; Fechar & quot; método que não faz as mesmas coisas que "Dispose", Close deve ser documentado como tal ou há um bug na classe. Eu nunca encontrei uma classe de framework que implementa IDisposable e um método Close () que introduziu um & quot; leak & quot; quando Close foi chamado sem chamar Dispose. O padrão esmagador para Dispose / Close é que Dispose calls Close, bem como a configuração de um & quot; disposed & quot; flag (usado para jogar ObjectDisposedException).
Na verdade, isso é detalhado na Referência Geral do Framework: "Ocasionalmente, um nome específico do domínio é mais apropriado que Dispose. Por exemplo, um encapsulamento de arquivo pode querer usar o nome do método Close. Nesse caso, implemente Dispose de forma particular e crie um método Close público que chame Dispose. O exemplo de código a seguir ilustra esse padrão. Você pode substituir Fechar por um nome de método apropriado ao seu domínio. & Quot; de Implementar Finalizar e Descartar para Limpar Recursos Não Gerenciados.
Assim como & quot; Para certas classes de objetos, como arquivos ou objetos de conexão com o banco de dados, um método Close representa melhor a operação lógica que deve ser executada quando o consumidor do objeto tiver terminado o objeto. & Quot; de Melhorando o Desempenho do Código Gerenciado (embora também detalhe "Em casos bem escritos, ambos são funcionalmente equivalentes". Isso implica que o uso de Close é mais claro com "representa melhor").
E, a propósito, um & quot; usando & quot; bloco não protege você também. Nada impede que você declare a variável fora do bloco (se bem me lembro), então ela ainda pode estar no escopo após o término do bloco. Você tem que ser diligente em escrever o código correto. Se você declarar no campo & quot; using & quot; declaração, isso é um caminho. Mas rejeitar usando a abordagem try / finally apenas porque deixa a variável no escopo não é realmente o ponto. Ainda precisa ser Dispose () em algum lugar.
Propriedade Process. StandardError.
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.
Obtém um fluxo usado para ler a saída de erro do aplicativo.
Assembly: System (no System. dll)
Valor da propriedade.
Um StreamReader que pode ser usado para ler o fluxo de erros padrão do aplicativo.
O fluxo StandardError foi aberto para operações de leitura assíncrona com BeginErrorReadLine.
Quando um processo grava texto em seu fluxo de erro padrão, esse texto é normalmente exibido no console. Ao redirecionar o fluxo StandardError, você pode manipular ou suprimir a saída de erro de um processo. Por exemplo, você pode filtrar o texto, formatá-lo de maneira diferente ou gravar a saída no console e em um arquivo de log designado.
Para usar o StandardError, você deve definir ProcessStartInfo. UseShellExecute como false e deve definir ProcessStartInfo. RedirectStandardError como true. Caso contrário, a leitura do fluxo StandardError gerará uma exceção.
O fluxo StandardError redirecionado pode ser lido de forma síncrona ou assíncrona. Métodos como Read, ReadLine e ReadToEnd executam operações de leitura síncrona no fluxo de saída de erro do processo. Essas operações de leitura síncrona não são concluídas até que o Processo associado grave em seu fluxo StandardError ou feche o fluxo.
Por outro lado, BeginErrorReadLine inicia operações de leitura assíncrona no fluxo StandardError. Esse método ativa um manipulador de eventos designado para a saída do fluxo e retorna imediatamente ao responsável pela chamada, que pode executar outro trabalho enquanto a saída do fluxo é direcionada para o manipulador de eventos.
As operações de leitura síncrona introduzem uma dependência entre a leitura do responsável pela chamada do fluxo StandardError e a gravação do processo filho nesse fluxo. Essas dependências podem resultar em condições de deadlock. Quando o chamador lê o fluxo redirecionado de um processo filho, ele depende do filho. O chamador aguarda na operação de leitura até que o filho grave no fluxo ou feche o fluxo. Quando o processo filho grava dados suficientes para preencher seu fluxo redirecionado, ele depende do pai. O processo filho aguarda na próxima operação de gravação até que o pai leia o fluxo completo ou feche o fluxo. A condição de deadlock resulta quando o chamador e o processo filho aguardam um ao outro para concluir uma operação e nenhum deles pode prosseguir. Você pode evitar deadlocks avaliando dependências entre o chamador e o processo filho.
O seguinte código C #, por exemplo, mostra como ler de um fluxo redirecionado e aguardar a saída do processo filho.
O exemplo de código evita uma condição de deadlock chamando p. StandardError. ReadToEnd antes de p. WaitForExit. Uma condição de deadlock pode resultar se o processo pai chama p. WaitForExit antes de p. StandardError. ReadToEnd e o processo filho grava texto suficiente para preencher o fluxo redirecionado. O processo pai aguardaria indefinidamente que o processo filho fosse encerrado. O processo filho esperaria indefinidamente que o pai lesse o fluxo completo do StandardError.
Há um problema semelhante quando você lê todo o texto da saída padrão e dos fluxos de erro padrão. O seguinte código C #, por exemplo, executa uma operação de leitura nos dois fluxos.
O exemplo de código evita a condição de deadlock executando operações de leitura assíncrona no fluxo StandardOutput. Uma condição de deadlock resulta se o processo pai chamar p. StandardOutput. ReadToEnd seguido por p. StandardError. ReadToEnd e o processo filho grava texto suficiente para preencher seu fluxo de erro. O processo pai esperaria indefinidamente que o processo filho fechasse seu fluxo StandardOutput. O processo filho esperaria indefinidamente que o pai lesse o fluxo completo do StandardError.
Você pode usar operações de leitura assíncronas para evitar essas dependências e seu potencial de deadlock. Como alternativa, você pode evitar a condição de deadlock criando dois threads e lendo a saída de cada fluxo em um thread separado.
Você não pode mesclar operações de leitura assíncrona e síncrona em um fluxo redirecionado. Depois que o fluxo redirecionado de um processo é aberto no modo assíncrono ou síncrono, todas as operações de leitura adicionais nesse fluxo devem estar no mesmo modo. Por exemplo, não siga BeginErrorReadLine com uma chamada para ReadLine no fluxo StandardError ou vice-versa. No entanto, você pode ler dois fluxos diferentes em modos diferentes. Por exemplo, você pode chamar BeginOutputReadLine e, em seguida, chamar ReadLine para o fluxo StandardError.
Você está executando console & quot; cmd & quot; ?
Se sim, então você tem que digitar exit também.
// Processo finalizado antes do período de tempo limite.
// Imprime mensagem de erro?
Eu gostaria de tentar isso, mas é muito de um hack. Eu tenho muitos comandos diferentes que levam diferentes quantidades de tempo (30 segundos a 25 minutos) para que não haja configuração em tempo real que eu possa colocar sem destruir meu desempenho. Esta função tem funcionado corretamente para vários comandos nos últimos 6 meses e agora ela decide me sacar. Eu tentei em um computador diferente sem problemas (o que realmente está mexendo comigo). Eu sei que não é o redirecionamento de saída / erro porque um novo WINDOW está sendo criado no servidor que estou remoting. Assim que fecho essa janela, meu processo sai como esperado e a saída correta é exibida no lado do usuário.
Obrigado por sua ajuda, mas estou ficando realmente frustrado com esse problema.
Sem conhecer os detalhes da mensagem, estamos apenas adivinhando o problema.
Você já instalou o 3.5 beta ou o Visual Studio 2008 beta?
Como você está usando o processo para iniciar o programa, Process. Start (& quot; file. exe & quot;), ou você está usando ProcessStartInfo?
Não, eu tenho 2003 e 2005 instalado.
proc = new Process ();
procSI = new ProcessStartInfo ();
Eu então configurei um novo thread para o StandardError e o StandardOutput.
Eu então escrevo meus comandos e.
if (redirecionando para fora do padrão)
Iniciar discussão para st. Fora.
Se (redirecionando erro padrão)
Iniciar discussão para st. erro.
Proc. WaitForExit (); & lt; -------- é onde ocorre a janela Relatório de erros do Windows genérico.
Traduzi o que pude da janela que aparece.
Veja também: Microsoft Visual Studio 2005, clique aqui para exibir o artigo traduzido
Porque o problema ocorre, ele termina o Microsoft Visual Studio 2005. Aplicamos a inconveniência, não há desculpa.
Obrigado novamente por todo o seu tempo.
Por que você está fazendo isso? Você não possui esse fluxo, então você não deveria estar fechando.
Isso é um erro de digitação? Antes de você estar falando sobre uma variável chamada "proc", não "Proc". Então, isso é simplesmente uma referência nula porque você está tentando invocar um método em uma referência diferente de & quot; proc & quot ;?
Você não deseja fechar o objeto sIn até que o aplicativo seja encerrado se você estiver redirecionando. Se o aplicativo gravar na saída padrão ou ler na entrada padrão depois de você fechar um deles, isso poderá causar uma exceção.
Você tem o rastreamento de pilha dessa mensagem de erro?
Você não deseja fechar o objeto sIn até que o aplicativo seja encerrado se você estiver redirecionando.
Não se deve fechar nenhum desses fluxos. O objeto Process possui-os e é o responsável pela limpeza após ele mesmo. Deve-se, na melhor das hipóteses, chamar Process. Dispose () depois de terminar com o objeto Process.
Eu criei o StreamWriter sIn antes de criar o objeto Process do processo. Eu então redireciono a entrada após o comando proc. Start (), então como eu não possuo isso? Independentemente disso, eu posso fazer a mudança para mover o sIn. Close () para depois da chamada WaitForExit para ver se isso faz alguma alteração.
O Proc foi um tipo, deveria ter sido proc.
Novamente, não é uma mensagem de erro, portanto, não há rastreamento de pilha. Meu redirecionamento StandardError está vazio e o redirecionamento de saída padrão contém o que eu esperava, mas nada indicando um erro. É por isso que tudo ainda funciona depois de fechar a janela Relatório de erros do Windows.
Vou postar o que acontece depois de mover a linha sIn. Close () abaixo da linha WaitForExit ().
Você não deseja fechar o objeto sIn até que o aplicativo seja encerrado se você estiver redirecionando.
Não se deve fechar nenhum desses fluxos. O objeto Process possui-os e é o responsável pela limpeza após ele mesmo. Deve-se, na melhor das hipóteses, chamar Process. Dispose () depois de terminar com o objeto Process.
Ok, eu estou fazendo Process. Close no bloco finally do meu código, por isso deve ser cuidado então.
Perdoem o meu comentário "não possuírem" o que fiz anteriormente. Acabei de voltar do almoço e estava perdendo o fato de que o processo tem controle sobre isso.
Process. Close é o método recomendado para fechar os fluxos padrão de entrada e saída padrão (e padrão).
Eu ficaria surpreso se o método Dispose não chamasse Close, pelo menos como parte de sua operação. Eu preferiria usar o fato de que, como o Process implementa IDisposable (indiretamente através do Componente de extensão que o implementa), deve-se chamar Dispose e deixar isso para a limpeza apropriada. Eu não recomendaria chamar Process. Close em vez de, nem além de Process. Dispose.
Process. Close é o método recomendado para fechar os fluxos padrão de entrada e saída padrão (e padrão).
Eu ficaria surpreso se o método Dispose não chamasse Close, pelo menos como parte de sua operação. Eu preferiria usar o fato de que, como o Process implementa IDisposable (indiretamente através do Componente de extensão que o implementa), deve-se chamar Dispose e deixar isso para a limpeza apropriada. Eu não recomendaria chamar Process. Close em vez de, nem além de Process. Dispose.
Como eu tenho certeza que você sabe, estes são funcionalmente equivalentes:
using (SomethingDisposable myObject =.)
// use myObject aqui.
// use myObject aqui.
if (myObject! = null) myObject. Dispose ();
Portanto, se a primeira recomendação é usar um bloco de uso, o melhor seria chamar Dispose, não Close, quando, como você disse, você sabe que está pronto com o objeto.
Por apenas chamar Close em algo que implementa IDisposable, o desenvolvedor está potencialmente cometendo um erro. Se Dispose fizer alguma limpeza adicional além de apenas delegar para Close, o programador está se preparando para um bug apenas chamando Close.
Pode haver um caso para chamar Close, mas somente se você não tiver terminado com o objeto, como você indicou na parte inferior da sua última resposta. Mas quando terminar, ligue para Dispose.
Como eu tenho certeza que você sabe, estes são funcionalmente equivalentes:
using (SomethingDisposable myObject =.)
// use myObject aqui.
// use myObject aqui.
if (myObject! = null) myObject. Dispose ();
Portanto, se a primeira recomendação é usar um bloco de uso, o melhor seria chamar Dispose, não Close, quando, como você disse, você sabe que está pronto com o objeto.
Por apenas chamar Close em algo que implementa IDisposable, o desenvolvedor está potencialmente cometendo um erro. Se Dispose fizer alguma limpeza adicional além de apenas delegar para Close, o programador está se preparando para um bug apenas chamando Close.
Pode haver um caso para chamar Close, mas somente se você não tiver terminado com o objeto, como você indicou na parte inferior da sua última resposta. Mas quando terminar, ligue para Dispose.
DisposableClass obj = new DisposableClass ();
ID descartável descartável = obj como IDisposable;
if (descartável! = nulo)
Mas sim, é isso que uma declaração de uso é "funcionalmente equivalente" para; mas eu não concordo explicitamente chamando Dispose na presença de um & quot; Close & quot; O método deve ser a primeira escolha devido à falta de escopo com a chamada Dispose. Por exemplo, o seguinte:
using (Process process = new Process ())
. é um erro de sintaxe.
Enquanto o seguinte:
Process process = new Process ();
// não há como garantir "processar & quot; não vai.
// ser acessado após o acima.
É um erro de tempo de execução (ObjectDisposedException). Usando Close não causa o erro de tempo de execução:
Process process = new Process ();
É sempre melhor trocar um erro em tempo de compilação por um erro em tempo de execução.
Então, eu configurei um ponto de interrupção após a chamada proc. WaitForExit () e ainda não atingi este ponto de interrupção. Então parece que isso é um grande problema.
Então, eu configurei um ponto de interrupção após a chamada proc. WaitForExit () e ainda não atingi este ponto de interrupção. Então parece que isso é um grande problema.
Eu tinha o serviço funcionando, mas eu parei porque ele tinha funcionado por 2 horas e nunca tinha o ponto de interrupção que deveria ter atingido dentro de 10 minutos de mim começando meu cliente. Eu descomentei a linha sIn. Close () agora mesmo e reiniciei o serviço e o Cliente e tudo está funcionando como antes. Eu posso acertar o ponto de interrupção após o WaitForExit () e eu concluir, com a mensagem de relatório de erros do Windows ainda (como era antes).
Então, no meu caso, eu preciso fechar o fluxo de entrada para poder sair do processo como esperado. Existem outras ideias?
Eu posso recomment a linha sIn. Close () se você quiser checar alguma coisa.
Eu tinha o serviço funcionando, mas eu parei porque ele tinha funcionado por 2 horas e nunca tinha o ponto de interrupção que deveria ter atingido dentro de 10 minutos de mim começando meu cliente. Eu descomentei a linha sIn. Close () agora mesmo e reiniciei o serviço e o Cliente e tudo está funcionando como antes. Eu posso acertar o ponto de interrupção após o WaitForExit () e eu concluir, com a mensagem de relatório de erros do Windows ainda (como era antes).
Então, no meu caso, eu preciso fechar o fluxo de entrada para poder sair do processo como esperado. Existem outras ideias?
Eu posso recomment a linha sIn. Close () se você quiser checar alguma coisa.
Como você está usando a entrada padrão e a saída padrão? Você está usando algum método ReadLine?
Peter, meu ponto é:
Se você não chamar Dispose em um objeto que implementa (direta ou indiretamente) IDisposable, então você está apenas pedindo um bug. Eu não quero discutir isso sem parar. Você pode continuar do jeito que você faz, e eu vou ficar com o meu. Contanto que não tenhamos que manter o código um do outro, tudo bem.
E, a propósito, um & quot; usando & quot; bloco não protege você também. Nada impede que você declare a variável fora do bloco (se bem me lembro), então ela ainda pode estar no escopo após o término do bloco. Você tem que ser diligente em escrever o código correto. Se você declarar no campo & quot; using & quot; declaração, isso é um caminho. Mas rejeitar usando a abordagem try / finally apenas porque deixa a variável no escopo não é realmente o ponto. Ainda precisa ser Dispose () em algum lugar.
Eu tinha o serviço funcionando, mas eu parei porque ele tinha funcionado por 2 horas e nunca tinha o ponto de interrupção que deveria ter atingido dentro de 10 minutos de mim começando meu cliente. Eu descomentei a linha sIn. Close () agora mesmo e reiniciei o serviço e o Cliente e tudo está funcionando como antes. Eu posso acertar o ponto de interrupção após o WaitForExit () e eu concluir, com a mensagem de relatório de erros do Windows ainda (como era antes).
Então, no meu caso, eu preciso fechar o fluxo de entrada para poder sair do processo como esperado. Existem outras ideias?
Eu posso recomment a linha sIn. Close () se você quiser checar alguma coisa.
Como você está usando a entrada padrão e a saída padrão? Você está usando algum método ReadLine?
Novamente, isso não é uma exceção que está sendo lançada, por isso não estou vendo detalhes de exceção. Eu não vou diretamente para o bloco catch no meu código, volto DIRETAMENTE após a chamada WaitForExit (). A janela que estou recebendo é a mesma que você recebe quando QUALQUER produto da Microsoft fecha inesperadamente e o MS quer informações sobre o Crash. Então, novamente, não há detalhes de exceção. No entanto, em um dos Logs do sistema, estou recebendo uma mensagem (traduzida do japonês)
& quot; Devenv. exe aplicação erros ocorrem, versão 8.0.50727.762 dos erros ocorridos módulo msvcr80.dll, versão 8.0.50727.762, erros ocorridos endereço 0x00039001.
Para mais informações, visite o site www. microsoft. com/fwlink/events. asp e consulte o Helo and Support Center. & Quot;
Estou redirecionando a entrada Padrão para passar os diferentes comandos porque estava tendo problemas para fazer com que funcionassem como eu queria formar o StartInfo. Estou redirecionando os fluxos de saída e erro para verificar o que eles contêm depois que o processo foi encerrado. Isso permitirá que eu verifique qualquer coisa que eu gostaria em qualquer fluxo, uma vez que tenhamos terminado. Também não permito que nenhum dos threads de redirecionamento de saída ou erro se junte até que o processo tenha passado pela chamada WaitForExit.
Estou completamente perplexo.
Peter, meu ponto é:
Se você não chamar Dispose em um objeto que implementa (direta ou indiretamente) IDisposable, então você está apenas pedindo um bug. Eu não quero discutir isso sem parar. Você pode continuar do jeito que você faz, e eu vou ficar com o meu. Contanto que não tenhamos que manter o código um do outro, tudo bem.
Eu não concordo. Não é um "bug" para não chamar Dispose. Seus recursos não serão liberados imediatamente, mas o GC os liberará se precisar da memória (supondo que o padrão Dispose esteja adequadamente implementado e exista um finalizador). Se a turma que você está usando implementa um & quot; Fechar & quot; método que não faz as mesmas coisas que "Dispose", Close deve ser documentado como tal ou há um bug na classe. Eu nunca encontrei uma classe de framework que implementa IDisposable e um método Close () que introduziu um & quot; leak & quot; quando Close foi chamado sem chamar Dispose. O padrão esmagador para Dispose / Close é que Dispose calls Close, bem como a configuração de um & quot; disposed & quot; flag (usado para jogar ObjectDisposedException).
Na verdade, isso é detalhado na Referência Geral do Framework: "Ocasionalmente, um nome específico do domínio é mais apropriado que Dispose. Por exemplo, um encapsulamento de arquivo pode querer usar o nome do método Close. Nesse caso, implemente Dispose de forma particular e crie um método Close público que chame Dispose. O exemplo de código a seguir ilustra esse padrão. Você pode substituir Fechar por um nome de método apropriado ao seu domínio. & Quot; de Implementar Finalizar e Descartar para Limpar Recursos Não Gerenciados.
Assim como & quot; Para certas classes de objetos, como arquivos ou objetos de conexão com o banco de dados, um método Close representa melhor a operação lógica que deve ser executada quando o consumidor do objeto tiver terminado o objeto. & Quot; de Melhorando o Desempenho do Código Gerenciado (embora também detalhe "Em casos bem escritos, ambos são funcionalmente equivalentes". Isso implica que o uso de Close é mais claro com "representa melhor").
E, a propósito, um & quot; usando & quot; bloco não protege você também. Nada impede que você declare a variável fora do bloco (se bem me lembro), então ela ainda pode estar no escopo após o término do bloco. Você tem que ser diligente em escrever o código correto. Se você declarar no campo & quot; using & quot; declaração, isso é um caminho. Mas rejeitar usando a abordagem try / finally apenas porque deixa a variável no escopo não é realmente o ponto. Ainda precisa ser Dispose () em algum lugar.
Propriedade Process. StandardError.
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.
Obtém um fluxo usado para ler a saída de erro do aplicativo.
Assembly: System (no System. dll)
Valor da propriedade.
Um StreamReader que pode ser usado para ler o fluxo de erros padrão do aplicativo.
O fluxo StandardError foi aberto para operações de leitura assíncrona com BeginErrorReadLine.
Quando um processo grava texto em seu fluxo de erro padrão, esse texto é normalmente exibido no console. Ao redirecionar o fluxo StandardError, você pode manipular ou suprimir a saída de erro de um processo. Por exemplo, você pode filtrar o texto, formatá-lo de maneira diferente ou gravar a saída no console e em um arquivo de log designado.
Para usar o StandardError, você deve definir ProcessStartInfo. UseShellExecute como false e deve definir ProcessStartInfo. RedirectStandardError como true. Caso contrário, a leitura do fluxo StandardError gerará uma exceção.
O fluxo StandardError redirecionado pode ser lido de forma síncrona ou assíncrona. Métodos como Read, ReadLine e ReadToEnd executam operações de leitura síncrona no fluxo de saída de erro do processo. Essas operações de leitura síncrona não são concluídas até que o Processo associado grave em seu fluxo StandardError ou feche o fluxo.
Por outro lado, BeginErrorReadLine inicia operações de leitura assíncrona no fluxo StandardError. Esse método ativa um manipulador de eventos designado para a saída do fluxo e retorna imediatamente ao responsável pela chamada, que pode executar outro trabalho enquanto a saída do fluxo é direcionada para o manipulador de eventos.
As operações de leitura síncrona introduzem uma dependência entre a leitura do responsável pela chamada do fluxo StandardError e a gravação do processo filho nesse fluxo. Essas dependências podem resultar em condições de deadlock. Quando o chamador lê o fluxo redirecionado de um processo filho, ele depende do filho. O chamador aguarda na operação de leitura até que o filho grave no fluxo ou feche o fluxo. Quando o processo filho grava dados suficientes para preencher seu fluxo redirecionado, ele depende do pai. O processo filho aguarda na próxima operação de gravação até que o pai leia o fluxo completo ou feche o fluxo. A condição de deadlock resulta quando o chamador e o processo filho aguardam um ao outro para concluir uma operação e nenhum deles pode prosseguir. Você pode evitar deadlocks avaliando dependências entre o chamador e o processo filho.
O seguinte código C #, por exemplo, mostra como ler de um fluxo redirecionado e aguardar a saída do processo filho.
O exemplo de código evita uma condição de deadlock chamando p. StandardError. ReadToEnd antes de p. WaitForExit. Uma condição de deadlock pode resultar se o processo pai chama p. WaitForExit antes de p. StandardError. ReadToEnd e o processo filho grava texto suficiente para preencher o fluxo redirecionado. O processo pai aguardaria indefinidamente que o processo filho fosse encerrado. O processo filho esperaria indefinidamente que o pai lesse o fluxo completo do StandardError.
Há um problema semelhante quando você lê todo o texto da saída padrão e dos fluxos de erro padrão. O seguinte código C #, por exemplo, executa uma operação de leitura nos dois fluxos.
O exemplo de código evita a condição de deadlock executando operações de leitura assíncrona no fluxo StandardOutput. Uma condição de deadlock resulta se o processo pai chamar p. StandardOutput. ReadToEnd seguido por p. StandardError. ReadToEnd e o processo filho grava texto suficiente para preencher seu fluxo de erro. O processo pai esperaria indefinidamente que o processo filho fechasse seu fluxo StandardOutput. O processo filho esperaria indefinidamente que o pai lesse o fluxo completo do StandardError.
Você pode usar operações de leitura assíncronas para evitar essas dependências e seu potencial de deadlock. Como alternativa, você pode evitar a condição de deadlock criando dois threads e lendo a saída de cada fluxo em um thread separado.
Você não pode mesclar operações de leitura assíncrona e síncrona em um fluxo redirecionado. Depois que o fluxo redirecionado de um processo é aberto no modo assíncrono ou síncrono, todas as operações de leitura adicionais nesse fluxo devem estar no mesmo modo. Por exemplo, não siga BeginErrorReadLine com uma chamada para ReadLine no fluxo StandardError ou vice-versa. No entanto, você pode ler dois fluxos diferentes em modos diferentes. Por exemplo, você pode chamar BeginOutputReadLine e, em seguida, chamar ReadLine para o fluxo StandardError.
Comments
Post a Comment