Pergunta

Eu tenho esse método:

    private delegate void watcherReader(StreamReader sr);
    private void watchProc(StreamReader sr) {
        while (true) {
            string line = sr.ReadLine();
            while (line != null) {
                if (stop) {
                    return;
                }
                //Console.WriteLine(line);
                line = stripColors(line);
                txtOut.Text += line + "\n";

                line = sr.ReadLine();
            }
        }
    }

E ele lê os fluxos de um processo (cmd.exe). Quando o usuário fecha a janela cmd.exe, faz com que o uso da CPU para saltar para 100%. Ao jogar com o depurador, vejo que ele pára na sr.ReadLine () e nunca retorna. Porque este é assistir tanto o StandardErrorStream eo StandardOutputStream ele usa 100% em ambos os núcleos.

Aqui está mais alguns códigos do projeto se você precisar dele.

    [DllImport("User32")]
    private static extern int ShowWindow(int hwnd, int nCmdShow);   //this will allow me to hide a window

    public ConsoleForm(Process p) {
        this.p = p;
        p.Start();
        ShowWindow((int)p.MainWindowHandle, 0);   //0 means to hide the window.

        this.inStream = p.StandardInput;
        this.outStream = p.StandardOutput;
        this.errorStream = p.StandardError;

        InitializeComponent();

        wr = new watcherReader(watchProc);
        wr.BeginInvoke(this.outStream, null, null);
        wr.BeginInvoke(this.errorStream, null, null);
    }

    public void start(string[] folders, string serverPath) {

        this.inStream.WriteLine("chdir C:\\cygwin\\bin");
        this.inStream.WriteLine("bash --login -i");
        this.inStream.WriteLine("");
    }


    //code example from http://geekswithblogs.net/Waynerds/archive/2006/01/29/67506.aspx it is
    //to make the textbox autoscroll I don't understand what it does, but it works.
    #region autoscroll
    [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    const int WM_VSCROLL = 277;
    const int SB_BOTTOM = 7;

    private void txtOut_TextChanged(object sender, EventArgs e) {            
        IntPtr ptrWparam = new IntPtr(SB_BOTTOM);
        IntPtr ptrLparam = new IntPtr(0);
        SendMessage(((RichTextBox)sender).Handle, WM_VSCROLL, ptrWparam, ptrLparam); 
    }
    #endregion

    private void ConsoleForm_FormClosed(object sender, FormClosedEventArgs e) {
        this.stop = true;
        try {
            this.p.Kill();
        } catch (InvalidOperationException) {
            return;
        }
    }

Outra interessante disso é que nem sempre ocultar a janela cmd como é suposto. Ela esconde-lo pela primeira vez, e depois o segundo (ou depois) que não vai esconder isso. Isto é, quando o usuário pode fechar a janela do cmd.exe e fazer com que o readline para agir engraçado. Ele também nunca lê a última linha passada para cmd, a menos que ele sai.

Todas as sugestões sobre como corrigir isso?

Foi útil?

Solução

Sempre que você tem um loop while(true) em seu código que você vai atrelar sua CPU (ou pelo menos um núcleo) em 100%, a menos que você também tem uma maneira de sair do loop. No seu caso, você tem uma declaração return, mas em nenhum ponto do circuito que você nunca fazer qualquer coisa para a variável stop guardando-o.

Outras dicas

Gostaria de mudar:

while(true)

para:

while(!sr.EOS) {

}

É a melhor maneira de verificar para terminar o loop.

Esta parece ser uma questão interessante aqui. À primeira vista, parece que ReadLine tem um problema com o punho que está sendo fechado de debaixo dela enquanto ele está tentando ler dados, e, portanto, parece ser um bug no quadro. No entanto, não estou convencido de que facilmente que é um bug no framework .Net ...

No entanto, há um par de baixo nível questões aqui.

As outras respostas que tenho até agora sugerem que você modificar o loop while. Eu faria isso tão bem, mas eu não acho que esta é a raiz do seu problema. Você não precisa de um sono lá, porque você vai ter o seu wait state do ReadLine (), a menos que não há dados para ler, e ele só retorna um failue, então você vai 'tight-loop'. Então, certifique-se que está a verificar todas e quaisquer estados de erro durante este loop.

Se você não fizer isso, eu posso ver problemas.

Se tudo está funcionando como deveria, então, se eu fosse você, eu ia começar por tentar identificar se você pode duplicá-lo fora do seu programa com um pequeno programa de demonstração. Eu tenho certeza que há uma abundância de verificação de erros no manuseio Corrente do Framework. No entanto, parece que você está executando algumas coisas de Cygwin, e essa é a saída que você está lendo a partir do shell cmd.

Tente fazer um aplicativo simples que apenas cospe dados para stdout, e stderr, e certifique-se o fechamento do aplicativo enquanto você ainda está lendo ..

Além disso, use o depurador para ver que linha == após a falha ocorre.

Larry

Tendo while(true) sem dormir no circuito irá causar 100% de uso da CPU.

Você precisa dormir por uma certa quantidade de tempo ou sair do loop em algum momento para que o CPU pode fazer outra coisa.

No mínimo você deve fazer algo ao longo das linhas de:

while (sr.Peek() >= 0) 
{
    Console.WriteLine(sr.ReadLine());
    Thread.Sleep(0);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top