0

私はこの方法を持っています:

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

もう 1 つの興味深い点は、想定どおりにコマンド ウィンドウが常に非表示になるとは限らないことです。最初は非表示にしますが、2 回目 (またはそれ以降) は非表示にしません。これは、ユーザーが cmd.exe ウィンドウを閉じて、readline の動作がおかしくなる場合です。また、終了しない限り、cmd に出力された最後の行を読み取ることはありません。

これを修正する方法について何か提案はありますか?

4

4 に答える 4

9

私なら、変えるね:

while(true)

に:

while(!sr.EOS) {

}

ループの終了を確認するには、より良い方法です。

于 2009-01-14T19:54:17.710 に答える
7

コードにループがある場合は常に、while(true)ループから抜け出す方法がない限り、CPU (または少なくとも 1 つのコア) を 100% にペグします。あなたの場合、ステートメントがありますが、ループのどの時点でも、それを保護している変数returnに対して何もしません。stop

于 2009-01-14T19:53:49.207 に答える
1

ループ内でスリープwhile(true)しないと、CPU 使用率が 100% になります。

CPU が別の処理を実行できるように、ある程度の時間スリープするか、ある時点でループから抜け出す必要があります。

少なくとも、次の行に沿って何かを行う必要があります。

while (sr.Peek() >= 0) 
{
    Console.WriteLine(sr.ReadLine());
    Thread.Sleep(0);
}
于 2009-01-14T19:54:02.187 に答える
1

これはここで興味深い問題のようです。一見すると、ReadLine がデータを読み取ろうとしているときにハンドルがその下から閉じられるという問題があり、フレームワークのバグのように見えます。しかし、それが .Net フレームワークのバグであると簡単に確信することはできません...

ただし、ここにはいくつかの低レベルの問題があります。

これまでに得た他の回答はすべて、while ループを変更することを示唆しています。私もこれを行いますが、これがあなたの問題の根源ではないと思います。読み取るデータがない場合を除き、ReadLine() から待機状態を取得し、失敗を返すだけなので、そこでスリープする必要はありません。その後、「タイトループ」になります。したがって、このループ中にすべてのエラー状態を確認していることを確認してください。

そうしないと、問題が発生する可能性があります。

他のすべてが正常に機能している場合、私があなただったら、小さなデモ プログラムを使用してプログラムの外で複製できるかどうかを確認することから始めます。フレームワークの Stream 処理には、エラー チェックが十分に行われているはずです。ただし、Cygwin からいくつかのものを実行しているように見えます。これは、cmd シェルから読み取っている出力です。

stdout と stderr にデータを吐き出すだけの簡単なアプリを作成してから、まだ読んでいる間にアプリが閉じていることを確認してください。

また、デバッガーを使用して、障害が発生した後の行 == を確認します。

ラリー

于 2009-01-14T20:05:04.270 に答える