Beginforputreadline waitforexit
Eu tenho problema com a leitura da saída de um processo de forma assíncrona em c #. Eu encontrei algumas outras perguntas semelhantes neste site, mas elas realmente não me ajudam. Aqui está o que eu faço:
Faça o novo processo Set startinfo - FileName, Argumentos, CreateNoWindow (true), UseShellExecute (false), RedirectStandardOutput (true) Adicione o manipulador de eventos ao OutputDataReceived; Inicie o processo, BeginOutputReadLine e, em seguida, WaitForExit ().
Ele funciona bem, mas a saída do processo iniciado grava algumas porcentagens (%) que eu quero obter, mas não consigo, pois meu código lê linha por linha e as porcentagens não aparecem.
Obtener a solução de um comando de consola.
Para solucionar esse problema, realmente precisamos do código-fonte para reproduzir o problema, para que possamos investigar o problema internamente. Não é necessário que você envie a fonte completa do seu projeto. Nós só precisamos de uma amostra mais simples para reproduzir o problema. Você pode remover qualquer informação confidencial ou lógica de negócios dele.
A leitura do StandardOutput é realmente complicada. O problema é que você também precisa ler o fluxo de erros ao mesmo tempo. Se você não ler constantemente de ambos, um dos buffers poderá ficar cheio e o processo parecerá travar enquanto espera que você o leia. É por isso que você não pode chamar ReadToEnd nos fluxos.
Eu realmente resolvi isso uma vez para o caso geral e eu me chuto toda vez que penso sobre isso, porque eu não pensei em manter uma cópia desse código para mim. Acabei tendo dois threads de leitor processando os fluxos de saída e erro que passariam os resultados de volta ao thread principal.
Se você ainda precisar de ajuda, posso tentar resolver isso amanhã.
Eu escrevi um exemplo de código para mostrar como você pode ler a saída de outro processo de linha de comando:
static void Main (string [] args)
String exeFileName = & quot; output. exe & quot; ;
ProcessStartInfo info = new ProcessStartInfo (exeFileName);
// Redirecionar a saída padrão do processo.
info. RedirectStandardOutput = true;
info. RedirectStandardError = true;
// Defina UseShellExecute como false para redirecionamento.
info. UseShellExecute = false;
Process proc = new Process ();
proc. StartInfo = info;
// Defina nosso manipulador de eventos para ler de forma assíncrona a saída de classificação.
proc. OutputDataReceived + = new DataReceivedEventHandler (proc_OutputDataReceived);
proc. ErrorDataReceived + = new DataReceivedEventHandler (proc_ErrorDataReceived);
// Inicia a leitura assíncrona do fluxo de saída de classificação. Note esta linha!
static void proc_ErrorDataReceived (remetente do objeto, DataReceivedEventArgs e)
Console. WriteLine (& quot; Erro: & quot; e e. Dados);
static void proc_OutputDataReceived (remetente do objeto, DataReceivedEventArgs e)
Console. WriteLine (& quot; Dados de saída: & quot ;, e. Data);
Espero que isto ajude!
Bem, isso é certamente mais fácil do que eu costumava fazer.
Eu realmente resolvi isso uma vez para o caso geral e eu me chuto toda vez que penso sobre isso, porque eu não pensei em manter uma cópia desse código para mim. Acabei tendo dois threads de leitor processando os fluxos de saída e erro que passariam os resultados de volta ao thread principal.
O problema é que, de acordo com a documentação do MSDN (e com os meus próprios testes, que suportaram isso), "Any instance members [da classe Process] não tem garantia de segurança para thread." Portanto, sua solução multi-threading, em teoria, não deveria funcionar. Certamente não é recomendado pela MS. Obrigado pela sugestão embora.
Eu escrevi um exemplo de código para mostrar como você pode ler a saída de outro processo de linha de comando:
Obrigado por isso. Isso realmente parece funcionar (yay!). mas apenas de forma síncrona. Você pode usar esse método para obter com segurança todas as saídas stdout e stderr de um processo, mas o código deve aguardar até que o processo tenha saído antes de retornar. Tudo bem se você quiser lidar com apenas um processo de cada vez, então este é um bom começo. Infelizmente, minha maior ambição era ser capaz de lidar com vários de uma só vez, o que significaria criar um novo thread que chamava esse código para cada processo. O problema é que, como mencionado acima, os membros da instância da classe Process não são thread-safe, então isso não pode ser feito.
Então, obrigado pela ajuda de todos, e agora sabemos como lidar com esse problema de maneira síncrona. No entanto, se houver uma maneira de fazê-lo de forma assíncrona (isto é, disparar alguns threads que lidam com alguns processos diferentes e, em seguida, retornar imediatamente para manter a interface do usuário responsiva), eu gostaria de saber como fazer isso. . Enquanto isso, porém, vou ter que viver fazendo isso de maneira síncrona.
Processo . Método BeginOutputReadLine ()
A documentação de referência da API. NET tem uma nova página. Visite o Navegador da API. NET em docs. microsoft para ver a nova experiência.
Inicia operações de leitura assíncrona no fluxo StandardOutput redirecionado do aplicativo.
Assembly: System (no System. dll)
Uma operação de leitura assíncrona já está em andamento no fluxo StandardOutput.
O fluxo StandardOutput foi usado por uma operação de leitura síncrona.
O fluxo StandardOutput 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.
Siga estas etapas para executar operações de leitura assíncrona no StandardOutput para um processo:
Adicione seu manipulador de eventos ao evento OutputDataReceived. O manipulador de eventos deve corresponder ao System. Diagnostics. Assinatura de delegado DataReceivedEventHandler.
Chame BeginOutputReadLine para o processo. Esta chamada inicia operações de leitura assíncrona no StandardOutput.
Quando operações de leitura assíncrona são iniciadas, o manipulador de eventos é chamado toda vez que o Processo associado grava uma linha de texto em seu fluxo StandardOutput.
Você pode cancelar uma operação de leitura assíncrona chamando CancelOutputRead. A operação de leitura pode ser cancelada pelo chamador ou pelo manipulador de eventos. Após o cancelamento, você pode chamar BeginOutputReadLine novamente para retomar as operações de leitura assíncrona.
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.
Beginforputreadline waitforexit
Eu estou tentando iniciar um processo e pegue o StandardOutput e StandardError usando EventHandlers e BeginOutputReadLine. Eu posso iniciar o processo, mas recebo.
Exceção chamando & quot; BeginOutputReadLine & quot; com & quot; 0 & quot; argumento (s): & quot; Não é possível misturar operação síncrona e assíncrona no fluxo do processo. & quot;
Aqui está a minha função de lançamento:
Estou violando o modelo de segmentação Powershell? Obrigado!
Eu estou tentando iniciar um processo e pegue o StandardOutput e StandardError usando EventHandlers e BeginOutputReadLine. Eu posso iniciar o processo, mas recebo.
Exceção chamando & quot; BeginOutputReadLine & quot; com & quot; 0 & quot; argumento (s): & quot; Não é possível misturar operação síncrona e assíncrona no fluxo do processo. & quot;
A mensagem de erro está dizendo o que você está fazendo errado.
Você não pode atribuir funções a um processo síncrono. As funções não são delegadas, portanto, não funcionarão. Você precisa usar um modelo de evento ou usar a variação do asynch.
Use isso como um modelo:
Marcado como Resposta Oliver Lipkau Moderator quarta-feira, 12 de outubro de 2011 2:32.
Todas as respostas.
Eu acredito que você tenha alguns erros no seu código. Eu sou a pessoa mais humilde que você já conheceu.
Eu estou tentando iniciar um processo e pegue o StandardOutput e StandardError usando EventHandlers e BeginOutputReadLine. Eu posso iniciar o processo, mas recebo.
Exceção chamando & quot; BeginOutputReadLine & quot; com & quot; 0 & quot; argumento (s): & quot; Não é possível misturar operação síncrona e assíncrona no fluxo do processo. & quot;
A mensagem de erro está dizendo o que você está fazendo errado.
Você não pode atribuir funções a um processo síncrono. As funções não são delegadas, portanto, não funcionarão. Você precisa usar um modelo de evento ou usar a variação do asynch.
Use isso como um modelo:
Marcado como Resposta Oliver Lipkau Moderator quarta-feira, 12 de outubro de 2011 2:32.
Ok, eu não entendi a implementação do BeginOutputReadline. Eu pensei que isso funcionaria com o. WaitForExit - olhando para ele agora, vejo por que isso não acontece.
Em VB. NET, eu sei como 1) gerar threads para lidar com isso e eu sei que você pode colocar o processo em um loop 2) até que seja concluído como uma forma de lidar com isso.
Eu não quero fazer # 2. Existe uma maneira multithreaded ou assíncrona para ler a saída de um determinado processo como o processo está gerando?
Ok, eu não entendi a implementação do BeginOutputReadline. Eu pensei que isso funcionaria com o. WaitForExit - olhando para ele agora, vejo por que isso não acontece.
Em VB. NET, eu sei como 1) gerar threads para lidar com isso e eu sei que você pode colocar o processo em um loop 2) até que seja concluído como uma forma de lidar com isso.
Eu não quero fazer # 2. Existe uma maneira multithreaded ou assíncrona para ler a saída de um determinado processo como o processo está gerando?
Na verdade, a menos que você queira criar um delegado de evento. Mas então este é o PowerShell, não é VB. NET.
Você pode começar aqui e ver se o evento que você está procurando pode ser "viciado"
help Register-ObjectEvent - full.
A resposta marcada não resolve o problema com o qual o OP está lutando - isto é, redirecionando StdErr e StdOut e sofre com o bug de conflito discutido aqui:
& quot; 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 o fluxo StandardOutput completo. & Quot;
Eu também estou tentando a melhor resposta para fazer este trabalho no Powershell, mas todos os exemplos de código que estou executando em que usam System. Diagnostics. Process no powersehll estão replicando o deadlock nesta implementação ou não estão redirecionando stderr e stdout.
A solução que estou usando usa o cmdlet Start-Process da seguinte maneira:
Não é uma ótima solução, pois só redirecionará stdout e stderr para um arquivo de texto. mas funcionará o tempo todo e redirecionará stdout e stderr.
Se formos usar saída redirecionada, não usaremos espera. Esse foi o design de CreateProcess desde o NT4.
O uso de arquivos para capturar a saída funcionará porque um fluxo é anexado e envia uma leitura constante para o fluxo de saída. O fluxo de saída nunca é suspenso. Yu não pode fazer isso em um loop de código. O córrego corre o contexto do sistema do pecado eu acredito e começarei sempre a possibilidade de ler. A espera está no seu thread, então você não pode fazer uma leitura manual. É um impasse como afirmado.
O uso da leitura do console é geralmente porque estamos procurando por um prompt. Nesse caso, nunca esperamos a conclusão. O código ZTHe provavelmente será enviado para 'quit' e nós iremos verificar o processo e girá-lo até que ele seja desligado.
A questão aqui é que nós não podemos gerar um thead. Em VB ou C #, C nós apenas usamos threads separe para IO e um para espera. Melhor ainda, eu usaria um semáforo como ele pode capturar dinamicamente um desligamento inesperado.
Talvez a próxima versão do PowerSHell tenha boas possibilidades de multithreading.
Essa é apenas mais uma lição de que o Powershell é uma linguagem de script, não uma linguagem de programação e, por mais poderosa que seja, existem armadilhas.
O código de exemplo da Microsoft simplesmente não é abrangente o suficiente para um hacker Powerhell perceber que eles não podem chegar lá a partir daqui. Isso é o que me pegou e acredito no OP também, porque houve uma certa expectativa de que BeginOutputReadline implementou a mágica para fazer com que funcionasse threads que teriam resolvido o problema de bloqueio. Não, então acabamos aqui.
E uma ligeira correcção ao meu código - deixei de fora o sinalizador - wait que é necessário para o resto do código funcionar:
Essa é apenas mais uma lição de que o Powershell é uma linguagem de script, não uma linguagem de programação e, por mais poderosa que seja, existem armadilhas.
O código de exemplo da Microsoft simplesmente não é abrangente o suficiente para um hacker Powerhell perceber que eles não podem chegar lá a partir daqui. Isso é o que me pegou e acredito no OP também, porque houve uma certa expectativa de que BeginOutputReadline implementou a mágica para fazer com que funcionasse threads que teriam resolvido o problema de bloqueio. Não, então acabamos aqui.
E uma ligeira correcção ao meu código - deixei de fora o sinalizador - wait que é necessário para o resto do código funcionar:
Certo. O PowerShell é propositadamente limitado para torná-lo mais seguro para a população em geral e para reduzir os problemas que ocorrem com as linguagens compiladas.
Sim - o sinalizador de espera ajudaria, pois o arquivo pode não ter terminado o spool antes de o programa ser encerrado.
O Start-Process é um wrapper fraco na API do processo, mas protege os desavisados dos deadlocks porque você não pode redirecionar a entrada, exceto de um arquivo.
Você não precisa de esperar para redirecionar. Você precisa esperar pelos arquivos e como uma maneira fácil de detectar a terminação. Usando a API, isso tem que ser feito pesquisando o objeto do processo ou extraindo a saída e aguardando que o processo envie sua mensagem de término, em seguida, girando no status.
Isso é tudo demais para os administradores de scripts e, como você apontou, os deixará sem problemas.
Processo . Evento OutputDataReceived.
A documentação de referência da API. NET tem uma nova página. Visite o Navegador da API. NET em docs. microsoft para ver a nova experiência.
Ocorre toda vez que um aplicativo grava uma linha em seu fluxo StandardOutput redirecionado.
Assembly: System (no System. dll)
O evento OutputDataReceived indica que o processo associado gravou uma linha, terminando com um caractere de nova linha, para seu fluxo StandardOutput redirecionado.
O evento é ativado durante operações de leitura assíncrona no StandardOutput. Para iniciar operações de leitura assíncrona, você deve redirecionar o fluxo StandardOutput de um processo, adicionar seu manipulador de eventos ao evento OutputDataReceived e chamar BeginOutputReadLine. Posteriormente, o evento OutputDataReceived sinaliza cada vez que o processo grava uma linha no fluxo StandardOutput redirecionado, até que o processo saia ou chame CancelOutputRead.
O aplicativo que está processando a saída assíncrona deve chamar o método WaitForExit para garantir que o buffer de saída tenha sido liberado.
Eu estou tentando iniciar um processo e pegue o StandardOutput e StandardError usando EventHandlers e BeginOutputReadLine. Eu posso iniciar o processo, mas recebo.
Exceção chamando & quot; BeginOutputReadLine & quot; com & quot; 0 & quot; argumento (s): & quot; Não é possível misturar operação síncrona e assíncrona no fluxo do processo. & quot;
Aqui está a minha função de lançamento:
Estou violando o modelo de segmentação Powershell? Obrigado!
Eu estou tentando iniciar um processo e pegue o StandardOutput e StandardError usando EventHandlers e BeginOutputReadLine. Eu posso iniciar o processo, mas recebo.
Exceção chamando & quot; BeginOutputReadLine & quot; com & quot; 0 & quot; argumento (s): & quot; Não é possível misturar operação síncrona e assíncrona no fluxo do processo. & quot;
A mensagem de erro está dizendo o que você está fazendo errado.
Você não pode atribuir funções a um processo síncrono. As funções não são delegadas, portanto, não funcionarão. Você precisa usar um modelo de evento ou usar a variação do asynch.
Use isso como um modelo:
Marcado como Resposta Oliver Lipkau Moderator quarta-feira, 12 de outubro de 2011 2:32.
Todas as respostas.
Eu acredito que você tenha alguns erros no seu código. Eu sou a pessoa mais humilde que você já conheceu.
Eu estou tentando iniciar um processo e pegue o StandardOutput e StandardError usando EventHandlers e BeginOutputReadLine. Eu posso iniciar o processo, mas recebo.
Exceção chamando & quot; BeginOutputReadLine & quot; com & quot; 0 & quot; argumento (s): & quot; Não é possível misturar operação síncrona e assíncrona no fluxo do processo. & quot;
A mensagem de erro está dizendo o que você está fazendo errado.
Você não pode atribuir funções a um processo síncrono. As funções não são delegadas, portanto, não funcionarão. Você precisa usar um modelo de evento ou usar a variação do asynch.
Use isso como um modelo:
Marcado como Resposta Oliver Lipkau Moderator quarta-feira, 12 de outubro de 2011 2:32.
Ok, eu não entendi a implementação do BeginOutputReadline. Eu pensei que isso funcionaria com o. WaitForExit - olhando para ele agora, vejo por que isso não acontece.
Em VB. NET, eu sei como 1) gerar threads para lidar com isso e eu sei que você pode colocar o processo em um loop 2) até que seja concluído como uma forma de lidar com isso.
Eu não quero fazer # 2. Existe uma maneira multithreaded ou assíncrona para ler a saída de um determinado processo como o processo está gerando?
Ok, eu não entendi a implementação do BeginOutputReadline. Eu pensei que isso funcionaria com o. WaitForExit - olhando para ele agora, vejo por que isso não acontece.
Em VB. NET, eu sei como 1) gerar threads para lidar com isso e eu sei que você pode colocar o processo em um loop 2) até que seja concluído como uma forma de lidar com isso.
Eu não quero fazer # 2. Existe uma maneira multithreaded ou assíncrona para ler a saída de um determinado processo como o processo está gerando?
Na verdade, a menos que você queira criar um delegado de evento. Mas então este é o PowerShell, não é VB. NET.
Você pode começar aqui e ver se o evento que você está procurando pode ser "viciado"
help Register-ObjectEvent - full.
A resposta marcada não resolve o problema com o qual o OP está lutando - isto é, redirecionando StdErr e StdOut e sofre com o bug de conflito discutido aqui:
& quot; 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 o fluxo StandardOutput completo. & Quot;
Eu também estou tentando a melhor resposta para fazer este trabalho no Powershell, mas todos os exemplos de código que estou executando em que usam System. Diagnostics. Process no powersehll estão replicando o deadlock nesta implementação ou não estão redirecionando stderr e stdout.
A solução que estou usando usa o cmdlet Start-Process da seguinte maneira:
Não é uma ótima solução, pois só redirecionará stdout e stderr para um arquivo de texto. mas funcionará o tempo todo e redirecionará stdout e stderr.
Se formos usar saída redirecionada, não usaremos espera. Esse foi o design de CreateProcess desde o NT4.
O uso de arquivos para capturar a saída funcionará porque um fluxo é anexado e envia uma leitura constante para o fluxo de saída. O fluxo de saída nunca é suspenso. Yu não pode fazer isso em um loop de código. O córrego corre o contexto do sistema do pecado eu acredito e começarei sempre a possibilidade de ler. A espera está no seu thread, então você não pode fazer uma leitura manual. É um impasse como afirmado.
O uso da leitura do console é geralmente porque estamos procurando por um prompt. Nesse caso, nunca esperamos a conclusão. O código ZTHe provavelmente será enviado para 'quit' e nós iremos verificar o processo e girá-lo até que ele seja desligado.
A questão aqui é que nós não podemos gerar um thead. Em VB ou C #, C nós apenas usamos threads separe para IO e um para espera. Melhor ainda, eu usaria um semáforo como ele pode capturar dinamicamente um desligamento inesperado.
Talvez a próxima versão do PowerSHell tenha boas possibilidades de multithreading.
Essa é apenas mais uma lição de que o Powershell é uma linguagem de script, não uma linguagem de programação e, por mais poderosa que seja, existem armadilhas.
O código de exemplo da Microsoft simplesmente não é abrangente o suficiente para um hacker Powerhell perceber que eles não podem chegar lá a partir daqui. Isso é o que me pegou e acredito no OP também, porque houve uma certa expectativa de que BeginOutputReadline implementou a mágica para fazer com que funcionasse threads que teriam resolvido o problema de bloqueio. Não, então acabamos aqui.
E uma ligeira correcção ao meu código - deixei de fora o sinalizador - wait que é necessário para o resto do código funcionar:
Essa é apenas mais uma lição de que o Powershell é uma linguagem de script, não uma linguagem de programação e, por mais poderosa que seja, existem armadilhas.
O código de exemplo da Microsoft simplesmente não é abrangente o suficiente para um hacker Powerhell perceber que eles não podem chegar lá a partir daqui. Isso é o que me pegou e acredito no OP também, porque houve uma certa expectativa de que BeginOutputReadline implementou a mágica para fazer com que funcionasse threads que teriam resolvido o problema de bloqueio. Não, então acabamos aqui.
E uma ligeira correcção ao meu código - deixei de fora o sinalizador - wait que é necessário para o resto do código funcionar:
Certo. O PowerShell é propositadamente limitado para torná-lo mais seguro para a população em geral e para reduzir os problemas que ocorrem com as linguagens compiladas.
Sim - o sinalizador de espera ajudaria, pois o arquivo pode não ter terminado o spool antes de o programa ser encerrado.
O Start-Process é um wrapper fraco na API do processo, mas protege os desavisados dos deadlocks porque você não pode redirecionar a entrada, exceto de um arquivo.
Você não precisa de esperar para redirecionar. Você precisa esperar pelos arquivos e como uma maneira fácil de detectar a terminação. Usando a API, isso tem que ser feito pesquisando o objeto do processo ou extraindo a saída e aguardando que o processo envie sua mensagem de término, em seguida, girando no status.
Isso é tudo demais para os administradores de scripts e, como você apontou, os deixará sem problemas.
Processo . Evento OutputDataReceived.
A documentação de referência da API. NET tem uma nova página. Visite o Navegador da API. NET em docs. microsoft para ver a nova experiência.
Ocorre toda vez que um aplicativo grava uma linha em seu fluxo StandardOutput redirecionado.
Assembly: System (no System. dll)
O evento OutputDataReceived indica que o processo associado gravou uma linha, terminando com um caractere de nova linha, para seu fluxo StandardOutput redirecionado.
O evento é ativado durante operações de leitura assíncrona no StandardOutput. Para iniciar operações de leitura assíncrona, você deve redirecionar o fluxo StandardOutput de um processo, adicionar seu manipulador de eventos ao evento OutputDataReceived e chamar BeginOutputReadLine. Posteriormente, o evento OutputDataReceived sinaliza cada vez que o processo grava uma linha no fluxo StandardOutput redirecionado, até que o processo saia ou chame CancelOutputRead.
O aplicativo que está processando a saída assíncrona deve chamar o método WaitForExit para garantir que o buffer de saída tenha sido liberado.
Комментарии
Отправить комментарий