2011-07-24 19 views
3

スレッドが他のスレッドのコントロールに直接アクセスできないと聞いたことがあります。ThreadPoolは他のスレッドのコントロールに直接アクセスできますか?

だから、私たちの教授は、私たちに

private void UpdateUI() 
{ 
    if(this.InvokeRequired) 
     this.Invoke(new MethodInvoker(UpdateUI)); 
    else 
     this.Refresh(); 
} 

スニペットを与え、それはスレッドがコントロールの所有者ではないし、我々は実行するために、所有者のスレッドを伝えるためにInvoke()メソッドを呼び出す必要がありInvokeRequiredプロパティがfalseを返すと言っUpdateUI()方法。その後、UIを更新します。

しかし、最近になって、ただ好奇心から、私はInvokeRequiredInvoke()

private void UpdateUI() 
{ 
    //if(this.InvokeRequired) 
     //this.Invoke(new MethodInvoker(UpdateUI)); 
    //else 
     this.Refresh(); 
} 

をコメントし、ThreadPoolのは、別のスレッドのコントロールにアクセスすることができましたし、今私は、私は完全の概念を理解していないと感じていることを見て驚きましたThreadPool。

ここに完全なコードがあります。

using System; 
using System.Threading; 
using System.Drawing; 
using System.Windows.Forms; 

class MainForm : Form 
{ 
    public MainForm() 
    { 
     this.Text = "Hello WinForms"; 
     ThreadPool.QueueUserWorkItem(Clock); 
    } 

    private void Clock(object state) 
    { 
     for(;;) 
     { 
      Thread.Sleep(1000); 
      UpdateUI(); 
     } 
    } 

    private void UpdateUI() 
    { 
     //if(this.InvokeRequired) 
     // this.Invoke(new MethodInvoker(UpdateUI)); 
     //else 
      this.Refresh(); 
    } 

    protected override void OnPaint(PaintEventArgs pe) 
    { 
     using(Pen pen = new Pen(Color.Red, 2)) 
      pe.Graphics.DrawRectangle(pen, 20, 20, 125, 30); 

     pe.Graphics.DrawString(DateTime.Now.ToString(), this.Font, Brushes.Blue, 25, 30); 
    } 

    [STAThread] 
    public static void Main() 
    { 
     Application.Run(new MainForm()); 
    } 
} 

私に説明してもらえますか?

ありがとうございました。

答えて

3

投稿したアプリケーションでは、ThreadPoolからコントロールにアクセスしていないため、フォーム上でのみRefreshを呼び出しています。これは実際にフォームにメッセージを送信して自身を再描画するように指示しますが、そのメッセージはThreadPoolスレッドではなくGUIのメインスレッドで受信されます。

したがって、スレッド間の操作を行わないため、あなたのケースで呼び出す必要はありません。 OnPaintメソッドは、Refreshメソッドから直接ではなく、Windowsメッセージポンプ経由で間接的に呼び出されます。

たとえば、テキスト・ボックスのテキストをバックグラウンド・スレッドから設定しようとすると、例外がスローされ、それを動作させるにはInvokeパターンを使用する必要があります。

+1

+1 @Searockあなたは 'OnPaint'メソッドで' Console.WriteLine(Thread.ManagedThreadId);を呼び出すことでその効果を見ることができるので、UIスレッドからのみ呼び出されることがわかります。 –

1

他のスレッドから要素にアクセスできますが、安全ではありません。

複数のスレッドが同時にコントロールにアクセスしようとすると、例外がスローされます。 WFはスレッドセーフではないためです。

3

ThreadPoolは、コードを実行するために使用できる再利用可能なスレッドスレッドのプールです。 ThreadPoolスレッドは、UIスレッドとは別のスレッドで実行されます。

あなたはUIスレッドに関心があります。どのスレッドもUIスレッドにアクセスできますが、スレッドセーフではありません。それがここのキーワードです。それはうまくいくかもしれない、そうでないかもしれない。もしそうなら、あなたには幸運がありました。

スレッドセーフではないということは、一貫した期待動作が保証されていないことを意味します。何かを設定すると動作するかもしれませんが、1ミリ秒後には無作為に失敗する可能性があります。

デフォルトでは.NETはクロススレッドコールをチェックしますが、これを無効にして、スレッドセーフでないコンテキストではSystem.Windows.Forms.Control.CheckForIllegalCrossThreadCallsfalseに設定することでUIにアクセスできます。しかし、これを無効にするということは、ランダムな行動を期待し、対応する必要があることを意味します。

関連する問題