2011-07-24 31 views
3

我聽說該線程無法直接訪問其他線程的控件。ThreadPool如何直接訪問另一個線程的控件?

因此,我們的教授給我們一個片段

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

,並表示InvokeRequired屬性返回false它的線程是不是控制的所有者,那麼,我們應該呼籲Invoke()方法來告訴主人線程來執行UpdateUI()方法。然後更新UI。

但最近,出於好奇我評論InvokeRequiredInvoke()

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

,驚訝地看到,線程池可以訪問另一個線程的控制,現在我覺得我還沒有完全瞭解的概念線程池。

以下是完整的代碼。

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。這實際上將消息發送到形式告訴自己重繪本身,而是在主界面線程,而不是從線程池線程收到該消息。

因此,你不必在你的情況下調用,因爲你沒有做任何跨線程活動。 OnPaint方法通過Windows消息泵間接調用,而不是直接從Refresh方法調用。

如果你嘗試,例如,設置從後臺線程文本框的文本......它會拋出一個異常,你將需要使用Invoke模式,使其工作。

+1

+1,@Searock你可以通過在'OnPaint'方法中調用'Console.WriteLine(Thread.ManagedThreadId)'來看到效果,所以你會看到它只從UI線程調用。 –

1

您可以從其他線程訪問元素,但它不安全。

如果有多個線程試圖訪問您同時控制它會引發異常。因爲WF控件不是線程安全的。

3

ThreadPool可重複使用線程,你可以用它來執行代碼池。 ThreadPool線程在單獨的線程上運行到UI線程。

你關心的是UI線程。任何線程都可以訪問UI線程,但是,它不是線程安全。這是關鍵詞。它可能有效,可能不會。如果確實如此,那麼你有幸運。

非線程安全只是意味着您無法保證一致的預期行爲。現在設置一些東西可能會奏效,但在毫秒後,它可能會無故地隨機失敗。

使用WinForms,默認情況下.NET會檢查跨線程調用,但我們可以通過將System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls設置爲false來禁用此功能,並在非線程安全的上下文中訪問UI。但是,禁用這意味着我們需要預期並迎合隨機行爲。

相關問題