程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#多線程demo

C#多線程demo

編輯:C#入門知識

首先,我們寫個簡單的單線程程序,也就是只有程序自己創建的那個主線程,沒有使用多線程.   創建一個新工程,向窗口添加一個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 } } } }   這樣,一個簡單的多線程程序就算完成了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved