2012-01-03 17 views
1

私は何日かの間、コンソールの更新テキストボックスを実行する方法を理解しようとしています。私は、フォームとコンソールプロセスを同時に実行するにはスレッドが絶対に必要であるという結論に達しました。プロセス自体はスタンドアロンのプログラムなので標準出力を使って情報を取得していますが、テキストボックスを更新する必要がない場合はうまくいくでしょうが、問題はプロセスの実行後にのみ更新されるということです私は実際にはマルチスレッドを使用しています。相続人他のスレッドが完了した後、テキストボックスのみが更新されます

private static readonly object _locker = new object(); 
    volatile string exchange = ""; 
    delegate void CallDelegate(string filename); 

機能自体::

public void CallConsole(string filename) 
    { 
     Thread.CurrentThread.Name = "ProccessThread"; 
     Thread.CurrentThread.IsBackground = false; 
     Process p = new Process(); 
     p.StartInfo.UseShellExecute = false; 
     p.StartInfo.RedirectStandardOutput = true; 
     p.StartInfo.RedirectStandardError = true; 
     p.StartInfo.FileName = filename; 
     if (checkBox1.Checked) 
      p.StartInfo.CreateNoWindow = true; 
     string output; 
     p.Start(); 
     while (!p.HasExited) 
     { 
      lock (_locker) 
      { 
       output = p.StandardError.ReadToEnd(); 
       if (output.Length != 0) 
       { 
        exchange = output; 
        Thread.Sleep(100); 
        MessageBox.Show(output); 
       } 
       output = p.StandardOutput.ReadToEnd(); 
       exchange = output; 
       System.Threading.Thread.Sleep(100); 
      } 
     } 
    } 

は、プロセスを実行し、私はスレッドとロックの間で情報を交換するために使用した出力だけでなく、文字列を扱う機能の委譲を行うことの始まりです

そして、ここではbutton_click後、プログラムの実行だ

private void button1_Click_1(object sender, EventArgs e) 
    { 
     textBox2.Text = ""; 
     //Thread.CurrentThread.Name = "Main"; 
     CallDelegate call = new CallDelegate (CallConsole); 
     IAsyncResult tag = call.BeginInvoke(textBox1.Text, null, null); 
     button1.IsAccessible = false; 
     while (!tag.IsCompleted) 
     { 
      string temp = ""; 
      lock (_locker) 
      { 
       Thread.Sleep(50); 
       if (exchange.Length != 0) 
       { 
        temp = exchange; 
        exchange = ""; 
       } 
      } 
      if (temp.Length != 0) 
       textBox2.Text = textBox2.Text + temp; 
     } 
     call.EndInvoke(tag); 
     button1.IsAccessible = true; 
    } 

注: textbox1はファイルパスです textbox2は読み取り専用です複数行テキストボックス

なぜCallConsoleの後に更新が行われるのですか?

答えて

7

一般的な問題:あなたはbutton1_Click_1の間でループしており、効果的にUIスレッドをブロックしています。これにより、他のイベント(再描画など)が処理されなくなります。

あなたはそうしてはいけません。代わりに、何かをポーリングする場合は、ポーリングを行うタイマーを設定し、UIが「アイドル」時間のイベントを処理できるようにします。

より当面の問題:あなたは未完のプロセスからの読者にReadToEndを呼んでいます。これはプロセスが完了するまでブロックされます(私は信じます)。 (完了する前に、読者には「終わり」はありません)。つまり、プロセスが完了するまで、ロックを保持しているスレッドが1つあり、そのロックを取得しようとしています。 UIスレッド。

私はまた、すべてのことをポールに依存しないようにすることをお勧めします。Processクラスのイベントを見て、別のスレッドでブロックする代わりにそれらを処理してみてください。これらのイベントのいずれかが発生すると、UIスレッド(Control.Invoke)にポストバックしてUIを更新することができます。何もないをポーリングする必要があります。

+0

私はJon SkeetがSOとC#に起こった最高のものの1つだと思います。 – Burimi

関連する問題