首先,我們寫個簡單的單線程程序,也就是只有程序自己創建的那個主線程,沒有使用多線程. 創建一個新工程,向窗口添加一個label命名為label1;我們要讓程序運行時label1就顯示一個數字,假設為100;通常我們會直接在窗口加載事件中寫label1.Text = “100″;這樣,運行 ,label1果然顯示了100; 代碼如下:(例1) using System; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “100″; } } } 很簡單吧,看懂了嗎?? 什麼,沒有,啊~~~神啊~~~救救我吧,那請你在翻書,把最最最最最基礎的書翻出來看看裡面的最最最最最簡單例子(以後不要說我認識你) 好了,看懂的朋友繼續往下看: 我們現在要將程序稍稍改動一下,添加一個Button,命名為button1,我們要在按下button1後,將lable1的text從0顯示到100, 那麼,我們需要添加button1的Click事件,在click事件內寫入循環顯示0到100. 代碼如下:(例2) using System; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “0″; } private void button1_Click(object sender, EventArgs e) { for(int i=0;i<101;i++) { label1.Text = i.ToString(); } } } } 運行一下看看,按一下button1,結果是我們一下就看到了100,並沒有看到0~100的過程,為什麼呢? 呵呵,因為你的處理器速度太快了,就只能看到最後的結果,那麼,怎樣才能看到中間過程呢?(等一下再講) 我們先用函數的方式來實現上面的功能 寫個名為run的函數吧: private void run() { for(int i=0;i<101;i++) { label1.Text = i.ToString(); } } 這樣就可以直接調用run函數實現功能了,而不用在事件函數內寫代碼。(這樣做是有好處的) 整個代碼如下:(例3) using System; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “0″; } private void button1_Click(object sender, EventArgs e) { run(); //調用run函數 } private void run() { for(int i=0;i<101;i++) { label1.Text = i.ToString(); } } } } 這裡就需要在循環過程中加延時了,假定我們每隔1s的延時,lable1的值增加1。 方法有很多,我們就用一個timer來實現延時。 添加一個timer, 命名為timer1,在timer1的tick事件內添加語句,改變label1的值。(Tick事件是每經過指定時間間隔後被觸發) 代碼如下:(例4) using System; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { int i; //全局變量i public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “0″; } private void button1_Click(object sender, EventArgs e) { run(); } private void run() { i = 0; timer1.Interval = 1000; //設置timer1的間隔時間 timer1.Start(); //啟動timer1 } private void timer1_Tick(object sender, EventArgs e) //timer1的Tick事件 { i++; if (i > 100) { timer1.Stop(); } label1.Text = i.ToString(); } } } 同樣的,我們運行一下,看看結果,很好,我們能夠看到0~100循環的過程了。 下面我們就要進入多線程了,不知道各位將上面的內容看懂了沒有? 開始進入多線程之前我還是先簡單的說說定義線程吧。(與多線程有關的其它內容我就不說了吧,那個太多太多了) 由於要使用多線程,我們需要引用System.Threading;所以之後的代碼都會在前面加上using System.Threading; 怎麼定義線程呢?通過下面的語句就定義一個名為thread1的線程 private Thread thread1; 和定義函數極為相似 定義線程之後,就要進行實例化: thread1 = new Thread(new ThreadStart(run)); 這個語句的意思就是實例化thread1並將run函數設定為thread1的入口函數(大概意思就是,讓run函數在線程thread1上執行,我是這樣理解的) 創建線程就算完成了,那麼怎麼運行線程呢? 其實和啟動timer1是類似的,thread1.Start();就運行了我們創建的線程thread1。 好了,大功告成!哈哈,別著急,既然我們創建了線程,那麼在關閉窗口的時候,就要撤消線程。 添加FormClosing事件,在事件內部寫如撤消線程的代碼: private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (thread1.IsAlive) //判斷thread1是否存在,不能撤消一個不存在的線程,否則會引發異常 { thread1.Abort(); //撤消thread1 } } 這樣才算大功告成嘛,整理的代碼如下:(例5)(在例3的基礎上加以改動) using System; using System.Threading; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { private Thread thread1; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “0″; } private void button1_Click(object sender, EventArgs e) { thread1 = new Thread(new ThreadStart(run)); thread1.Start(); } private void run() { for (int i = 0; i < 101; i++) { label1.Text = i.ToString(); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (thread1.IsAlive) { thread1.Abort(); } } } } 運行看看,按button1,出錯了,怎麼回事呢???? 哈哈~~看看出錯原因,是在run函數內的label1.Text = i.ToString();語句上出的錯,沒錯啊,語法正確啊 哈哈~~我來解釋一下,出錯的原因是為了保護數據的安全所以不能跨線程調用控件,而label1.Text = i.ToString();句則是在線程thread1上面調用主線程的控件,肯定會出錯的 !! 怎麼辦呢?用委托啊(有關委托,請參考其它資料,我就不多說了) 我的理解就是,線程thread1不能調用主線程的lable1,所以,就委托主線程來改變lable1的值。 首先看一個例子:(從例3改寫)(並不創建線程,僅有主線程) 創建一個函數,用來設置lable1的值; private void set_lableText(string s) { label1.Text = s; } 當需要改變lable1的值時,就調用它,並傳遞要改變的值。 整理代碼如下:(例6) using System; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “0″; } private void button1_Click(object sender, EventArgs e) { run(); //調用run函數 } private void run() { for(int i=0;i<101;i++) { set_lableText( i.ToString() ); } } private void set_lableText(string s) { label1.Text = s; } } } 實現的功能與例3是一樣的,只是,增加了一個函數。 現在再來看看委托,我們就需要委托主線程調用函數set_lableText(string s);來改變lable1的值。 首先聲明一個委托: delegate void set_Text(string s); 創建一個全局委托變量:(應該是變量吧) set_Text Set_Text; //請注意大小寫,set_Text是委托類型,Set_Text是創建的委托(當然,這裡的命名是隨意的) 類似於創建線程,需要進行實例化: Set_Text = new set_Text(set_lableText); //括號內的set_lableText是委托要調用的函數(也就是例6寫的set_lableText(string s);函數) 現在,就剩下調用委托了,怎麼調用委托呢?很簡單。 同過Invoke來調用,語句如下: label1.Invoke(Set_Text, new object[] { i.ToString() }); //Set_Text是調用的委托,object[]則是我們要傳遞的參數 整理代碼如下:(例7) using System; using System.Threading; using System.Windows.Forms; namespace ThreadTest { public partial class Form1 : Form { private Thread thread1; //定義線程 delegate void set_Text(string s); //定義委托 set_Text Set_Text; //定義委托 public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { label1.Text = “0″; Set_Text = new set_Text(set_lableText); //實例化 } private void button1_Click(object sender, EventArgs e) { thread1 = new Thread(new ThreadStart(run)); thread1.Start(); } private void set_lableText(string s) //主線程調用的函數 { label1.Text = s; } private void run() { for (int i = 0; i < 101; i++) { label1.Invoke(Set_Text, new object[] { i.ToString() }); //通過調用委托,來改變lable1的值 Thread.Sleep(1000); //線程休眠時間,單位是ms } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (thread1.IsAlive) //判斷thread1是否存在,不能撤消一個不存在的線程,否則會引發異常 { thread1.Abort(); //撤消thread1 } } } } 這樣,一個簡單的多線程程序就算完成了。