hey,you guys.
好久不見了,最近忙著學習英文,處理一些雜事,所以沒有來得及更新博客。公司目前沒活,比較清閒。所以,有時間研究了一下<叩響C#之門>。據說作者是一位40多歲的初中數學老師,自學C#。40多歲的人自學編程,這份毅力很令人敬佩。這本書寫的,是C#語言的基礎知識。作者講解的很清楚,讀後很受益。很多之前一知半解,甚至一點都不懂得基礎原理,現在豁然開朗。就像孔子所說:“朝聞道,夕死可矣。”這本書,真的適合初級.NET程序員讀一下,真的很有幫助的。好了,書歸正傳,來開始我們今天的學習吧。
多線程這塊,在.NET中屬於深層次的技術了。今天,我們就來學習學習多線程的知識吧。
線程的概念
大家平時使用電腦,可以一邊聽音樂,一邊下載電影,一邊浏覽網頁。那麼電腦它是如何滿足用戶這種需求呢?原來操作系會創建三個應用程序,通過應用程序來執行用戶的操作。每個應用程序被看作一條連續的指令流,CPU一條條執行這些指令流。但是早一些的電腦CPU不允許同一時間執行多條指令流,那麼電腦又是如何做的呢?操作系統創建三個應用程序的同時,也創建了三個進程(Process)。進程不但包括了應用程序的指令流,還包括了運行應用程序所需的內存、寄存器等等。操作系統通過進程來執行應用程序。我們可以把進程看作是執行路線。操作系統 通過”時間片輪轉”來輪流執行這些進程。所以,宏觀上進程是並發執行的,在微觀上是交替進行的。也就是說,電腦並不是同時滿足聽音樂、下載電影、浏覽網頁的,CPU是交替執行的,只不過交替時間很短暫,我們感覺不到。我們設想這樣一個場景,一個網頁播放Flash的同時,網頁上還有一個文本框,來接受用戶的輸入。這個網頁需要一邊播放Flash,一邊接受用戶的輸入。Note (個人理解,CPU執行這個網頁的進程指令,同時這個進程還要執行播放Flash、接受用戶輸入這兩個指令)。如果是以前,我們需要很復雜的一段代碼來實現這個需求。但是多線程(Multi-Threading)技術的出現,就可以很容易的實現這個需求了。可以在網頁這個進程中創建兩個線程,通過這兩個線程來執行播放Flash、接受用戶輸入。我們可以把進程中的多個線程,看作是多條執行路線。一個進程中的多個線程,它們共享資源。所以,線程之間的切換要遠遠快於進程之間的切換,我們可以把線程看作是輕量級的進程(LightweightProcess)。操作系統通過調度程序來管理線程,不需程序員關心,我們只需編寫好線程即可,線程是CPU調度的基本單位。
Thread類
計算機運行某個應用程序時,會創建一個進程,進程會創建多個線程,通過線程來執行工作,我們把執行某些工作的線程稱為工作線程(Work Thread)。C#中,關於線程的處理,都是通過System.Threading命名空間下的Thread類來完成的。
Using System.Threading; //別忘了添加引用 //聲明一個線程的代碼 Thread workThread=new Thread(entryPoint);
entryPoint:是入口方法,線程會從入口方法的第一行代碼執行。大家應該可以看出,Thread類的構造函數的參數類型是一個委托類型。也就是說entryPoint的函數的返回值、參數取決於Thread類的構造函數的委托參數決定。
//Thread類的構造函數參數的委托類型 public delegate void ThreadStart(); public delegate void ParameterizedThreadStart(object obj);
入口方法,必須是ThreadStart或ParameterizedThreadStart的委托。
那麼綜上所述,如果要創建一個線程,需要兩步.
//第一步 創建入口方法 private void EntryPoint() { //線程的具體代碼 ........... ........... } //第二步 創建線程對象 Thread workThread=new Thread(EntryPoint);
線程的優先級
我們工作生活中,需要處理很多事情。一般當緊的事兒需要及時處理,不當緊的事兒可放在後面處理。線程處理指令也是一樣的,也分當緊與不當緊。通過Thread類的Priority屬性來設置線程的優先級。Priority屬性是一個ThreadPriority枚舉。這個枚舉有以下5個優先等級:
Normal、AboveNormal、Highest、BelowNormal、Lowest。
我們跑一下程序來測試一下線程優先級:
//workThread1線程 Thread workThread1 = new Thread(delegate() { for (int i = 0; i < 100000000; i++) { if (i % 1000000 == 0) { Console.Write("A"); } } }); //workThread2線程 Thread workThread2 = new Thread(delegate() { for (int i = 0; i < 100000000; i++) { if (i % 1000000 == 0) { Console.Write("B"); } } }); //啟動線程 workThread1.Start(); workThread2.Start();
運行程序,效果如下圖:
//workThread1線程 Thread workThread1 = new Thread(delegate() { for (int i = 0; i <= 500000000; i++) { if (i % 1000000 == 0) { Console.Write('A'); } } }); //workThread2線程 Thread workThread2 = new Thread(delegate() { for (int i = 0; i <= 500000000; i++) { if (i % 1000000 == 0) { Console.Write('B'); } } }); //修改Thread的優先級 workThread1.Priority = ThreadPriority.AboveNormal; workThread2.Priority = ThreadPriority.BelowNormal; //啟動線程 workThread1.Start(); workThread2.Start(); //主線程代碼 for (int i = 0; i <= 500000000; i++) { if (i % 1000000 == 0) { Console.Write('M'); } }
其實除了workThread1、workThread2還有一個主線程(Main Thread)。我們修改了一下主線程的代碼,以便觀察三個線程是如何交叉工作的。我們代碼中把workThread的Priority的屬性設置為高於一般(AboveNormal)、把workThread2的Priority屬性設置為低於一般(BelowNormal)。此時運行程序的效果如下圖:
static void Main(string[] args) { //workThread1線程 Thread workThread1 = new Thread(delegate() { for (int i = 0; i <= 500000000; i++) { if (i % 1000000 == 0) { Console.Write('A'); } } }); //workThread2線程 Thread workThread2 = new Thread(delegate() { for (int i = 0; i <= 50000000; i++) { if (i % 1000000 == 0) { Console.Write('B'); } } workThread1.Join(); for (int i = 0; i <= 50000000; i++) { if (i % 10000 == 0) { Console.Write('b'); } } }); //啟動線程 workThread1.Start(); workThread2.Start(); }
我們在線程workThread2的入口方法中,調用了workThread1的join()方法,此時當程序執行到join()方法時,workThread2就會停止工作,去執行workThread1,直到workThread1執行完畢,才會接著執行workThread2。程序運行結果如下圖:
Join()方法,還可以接受一個表示毫秒的參數,當達到這個時間,不論是否執行完畢,都會退出。
線程狀態
線程一共有7種狀態,它們分別是未開始狀態(UnStarted)、運行狀態(Running)、等待睡眠插入狀態(WaitSleepJoin)、掛起請求狀態(SuspendRequested)、掛起狀態(Suspended)、中止請求狀態(AbortRequested)、中止狀態(Stopped)。大家可以通過下面這幅圖片來認識這7中狀態:
1.未開始狀態(Unstarted)
當一個線程被創建,它的狀態會變為未開始狀態(UnStarted).
2.運行狀態(Running)
當線程調用Start()方法時,線程狀態就會變為運行狀態(Ruuning)。
3.等待睡眠插入狀態(WaitSleepJoin)
當運行狀態的線程調用方法Sleep()、Join()、或Wait()時,線程狀態會變為等待睡眠插入狀態(WaitSleepJoin).此時如果調用Pulse()或Interrupt()線程狀態會變為Running狀態。
4.掛起請求狀體(SuspendRequested)
當運行狀態的線程調用方法Suspend()的時,線程狀態會變為SuspendRequested。
5.掛起狀態(Suspended)
當調用Suspend()方法時,線程不會立馬被掛起,而是會處於SuspendRequested狀態,線程會再執行幾條指令,當確保線程在一個安全的狀態下,掛起線程,線程狀態變為Suspended。調用Resume()方法可以使線程狀體變為Running狀態。
6.中止請求狀態(AbortRequested)
當處於運行狀態的線程調用方法Abort()時,線程狀態會變為AbortRequested。
7.中止狀態(Aborted)
當線程調用Abort()方法時,線程不會馬上中止,而會處於AbortRequested狀態,再執行幾條指令,當確保線程在一個安全狀態下,中止線程,線程狀態變為Stopped。
是這樣的。我以前寫過FTP上傳。就是用多線程做的。
給你推薦一些比較好的教程吧,你應該用得著: 漫談C++ Builder多線程編程技術: www.it55.com/...5.html 用MFC編寫多線程程序實例: www.it55.com/...7.html C++寫的web服務器程序(多線程): www.it55.com/...9.html 後面兩個都是多線程的實例教程。