2011-02-09 40 views
4
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 


namespace testThreads 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 

     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 

     public void countToLots() 
     { 
      for (int i = 0; i < 10000000; i++) 
      { 
       textBox1.Text = "Counting to 10000000, value is " + i + Environment.NewLine; 
      } 
     } 

     public void countToZero() 
     { 
      for (int i = 10000000; i > 0; i--) 
      { 
       textBox2.Text = "Counting to 0, value is " + i + Environment.NewLine; 
      } 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      Thread countUp = new Thread(new ThreadStart(countToLots)); 
      Thread countDown = new Thread(new ThreadStart(countToZero)); 
      countUp.Start(); 
      countDown.Start(); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      textBox3.Text = "Bobby bob bob " + Environment.NewLine; 
     } 
    } 
} 

私は本当にこれを掛けなければなりません - 私はエラーメッセージが表示される理由を理解できません。誰かが私を助けてくれますか?スレッディングの基礎

クロススレッド操作有効ではありません:それは に作成されたスレッド以外のスレッドからアクセス コントロール「textBox1テキストボックス」。

答えて

5

UIコントロールには「スレッドアフィニティ」があります。彼らはUIスレッド以外の何かに触れたいと思っています。読み取りと書き込みのプロパティが含まれます。 .Textへの割り当ては、UIスレッドからInvokeまたはBackgroundWorkerのいずれかを使用して行う必要があります。例えば

public void countToLots() 
{ 
    for (int i = 0; i < 10000000; i++) 
    { 
     // running on bg thread 
     textBox1.Invoke((MethodInvoker) delegate { 
      // running on UI thread 
      textBox1.Text = "Counting to 10000000, value is " 
         + i + Environment.NewLine; 
     }); 
     // running on bg thread again 
    } 
} 

しかしノートスレッド切り替えのこのタイプは、オーバーヘッドを持っていること。すべての繰り返しを呼び出すべきではありません。たとえば、上記の例では10000ごとに[n]反復ごとにUIを更新する必要があります。

+0

私はまだ同じ方法でメソッドを呼び出しますか? – tom

+0

@tom yes; *コントロールに触れるのは痛みだけです。もちろん、それは単純化されています。 **複数のスレッドを持っている場合、**共有データ**にはたくさんの考えが必要です –

+0

この種の良い本をお勧めしますか?私は大学でそれをオプションとして勉強する機会を得ましたが、occam piは本当に私を – tom

2

フォームコントロールのメソッドまたはプロパティを、コントロールを作成した(新しいと呼ばれる)スレッドとは別のスレッドから使​​用することはできません。この方法は、BeginInvokeメソッドをもう一度コントロールを作成したスレッドからSetTextメソッドを呼び出しているとやっている

public void countToLots() 
    { 
     for (int i = 0; i < 10000000; i++) 
     { 
      SetText("Counting to 10000000, value is " + i + Environment.NewLine); 
     } 
    } 

    public void SetText(string text) 
    { 

     if (this.textBox1.InvokeRequired()) 
     { 
      Action<string> auxDelegate = SetText; 
      this.BeginInvoke(auxDelegate,text); 
     } 
     else 
     { 
      this.textBox1.Text = text; 
     } 
    } 

何:ちょうど行うことを行うには

1

いいえ、WHYコントロールの背後にある理論については、UIスレッドの親和性があります。

長時間プログラムしたことがある場合は、フォームと高速アプリケーション開発が標準ではない日を覚えているはずです。当時、コントロールをフォームにドロップするのはまれでした...すべては古い学校で行われました。

今、窓では、 "古い学校"の方法は、WindowProcを定義することに関係しています。

WindowProcはアプリケーションメッセージを処理するために呼び出される関数です(私が言うのはそうではありません)。この関数は、メインプログラムスレッド上で実行され、ユーザーインターフェイスのペイントや更新など、アプリケーションが受信するすべてのメッセージの処理を担当します。

最近ではすべてが自動化されているため、フォームを作成するときに、すべての作業を担当するコードが自動生成され、そのことについて心配する必要はありません。

もちろん、すべてのコントロールでユーザーインターフェイスを描画するスレッドがメインスレッドの場合は、別のスレッドからの変更によってアプリケーション自体が競合状態などに邪魔される可能性があります。さらに、UI処理は自動生成されるため、2つの標準スレッドで使用する同期メカニズムを置くことはできません。なぜなら、1つのスレッドでコードにアクセスできますが、メインのwindowprocコールバックにはアクセスできないからです。

BeginInvokeは、メインスレッドにメッセージを渡して、時間が間違っているときに自分のコンテキストで代理人を親切に処理し、実行をメインスレッドに委譲するように指示します。