先看以下代碼:
using System;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace 線程間通訊
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//1.建立Invoke函數,大致如下:
/// <summary>
/// Delegate function to be invoked by main thread
/// </summary>
private void InvokeFun()
{
if (prgBar.Value < 100)
{
prgBar.Value = prgBar.Value + 1;
button1.Text = prgBar.Value.ToString();
}
if (prgBar.Value == 100)
{
MessageBox.Show("完成", this.Text);
prgBar.Value = 0;
}
}
//2.子線程入口函數:
/// <summary>
/// Thread function interface
/// </summary>
private void ThreadFun()
{
//Create invoke method by specific function
MethodInvoker mi = new MethodInvoker( this.InvokeFun );
for( int i = 0; i < 100; i++ )
{
this.BeginInvoke( mi );//讓主線程去訪問自己建立的控制項.
Thread.Sleep( 100 );//在新的線程上執行耗時操作.
}
}
//3. Begin from here
private void button1_Click(object sender, EventArgs e)
{
Thread thdProcess = new Thread(new ThreadStart(ThreadFun));
thdProcess.Start();
}
}
}
在不做處理的情況下,如果子線程訪問由主線程建立的控制項時,系統都會報錯,告訴我們線程間不能直接調用.因為不同的線程是在不同的記憶體空間中各自無幹擾的並行運行著的.那麼要怎麼做才能讓在子線程中訪問到想要訪問的控制項呢?
其實,從上面的例子中可以看出,實現線程間通訊其實並不複雜.thdProcess.Start()以後,開始了一個新的線程,這個線程從入口函數ThreadFun()開始.下面就是問題的關鍵了:
代碼中用到了MethodInvoker 委託,在MSDN中是這樣描述它的:該委託可執行Managed 程式碼中聲明為 void 且不接受任何參數的任何方法,在對控制項的 Invoke 方法進行調用時或需要一個簡單委託又不想自己定義時可以使用該委託。在這裡它實際上就代表了InvokeFun()方法.
另一個重要的方法:BeginInvoke(Delegate) ,它表示在建立控制項的基礎控制代碼所線上程上非同步執行指定委託。它可非同步呼叫委託並且此方法立即返回。可以從任何線程(甚至包括擁有該控制項控制代碼的線程)調用此方法。如果控制項控制代碼尚不存在,則此方法沿控制項的父級鏈搜尋,直到它找到有視窗控制代碼的控制項或表單為止。這裡就是通過這個非同步呼叫來完成子線程對主線程上相應控制項的訪問的.
回頭想想,是不是很簡單的三步:建立並開始線程->指定委託方法->非同步呼叫.