为什么我的循环使用100%CPU并且永远不会结束?

时间:2009-01-14 19:45:36

标签: c# delegates readline streamreader

我有这个方法:

    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();
            }
        }
    }

它从进程(cmd.exe)读取流。当用户关闭cmd.exe窗口时,它会导致CPU使用率跳至100%。在使用调试器时,我发现它在sr.ReadLine()上停止并且永远不会返回。因为它正在观察StandardErrorStream和StandardOutputStream,所以它在两个核心上都使用了100%。

如果您需要,可以使用以下项目代码。

    [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;
        }
    }

另一个有趣的是它并不总是像它应该的那样隐藏cmd窗口。它第一次隐藏它,然后第二次(或之后)它不会隐藏它。这是用户可以关闭cmd.exe窗口并使readline行为有趣的时候。它也永远不会读取输出到cmd的最后一行,除非它退出。

有关如何解决此问题的任何建议吗?

4 个答案:

答案 0 :(得分:9)

我会改变:

while(true)

为:

while(!sr.EOS) {

}

这是检查结束循环的更好方法。

答案 1 :(得分:7)

每当你的代码中有while(true)循环时,你将以100%的方式将你的cpu(或至少一个核心)挂起,除非你还有办法摆脱循环。在你的情况下,你确实有一个return语句,但是在循环中没有任何一点你对保护它的stop变量做了什么。

答案 2 :(得分:1)

while(true)在循环中没有睡眠将导致100%的CPU使用率。

你需要睡一段时间或者在某个时候突然离开循环,这样CPU才能做其他事情。

至少你应该按照以下方式做点什么:

while (sr.Peek() >= 0) 
{
    Console.WriteLine(sr.ReadLine());
    Thread.Sleep(0);
}

答案 3 :(得分:1)

这似乎是一个有趣的问题。乍一看,ReadLine似乎有一个问题,即当它试图读取数据时句柄被关闭,因此似乎是框架中的一个错误。但是,我不相信它是.Net框架中的一个错误......

但是,这里有一些低级问题。

到目前为止你得到的其他答案都建议你修改while循环。我也会这样做,但我不认为这是你问题的根源。你不需要在那里休眠,因为你将从ReadLine()中获取你的等待状态,除非没有数据要读取,它只返回一个故障,那么你将“紧密循环”。因此,请确保在此循环期间检查任何和所有错误状态。

如果你不这样做,我可以看到问题。

如果其他一切正常,那么如果我是你,我会先尝试确定你是否可以通过一个小型演示程序在程序之外复制它。我确信框架的Stream处理中有大量的错误检查。但是,看起来你正在运行一些来自Cygwin的东西,这就是你从cmd shell中读取的输出。

尝试创建一个简单的应用程序,只将数据吐出到stdout和stderr,然后确保应用程序在您还在阅读时关闭..

还可以使用调试器查看失败发生后的行==。

拉​​里