C#多執行緒程式設計(1):執行緒的啟動

周公發表於2009-08-03

 在例項化Thread的例項,需要提供一個委託,在例項化這個委託時所用到的引數是執行緒將來啟動時要執行的方法。在.net中提供了兩種啟動執行緒的方式,一種是不帶引數的啟動方式,另一種是帶引數的啟動的方式。
 不帶引數的啟動方式
 如果啟動引數時無需其它額外的資訊,可以使用ThreadStart來例項化Thread,如下面的程式碼:

程式的執行效果我們不用執行也會知道,那就是在迴圈中將系統當前時間的毫秒部分輸出出來,在每次輸出之後會將當前執行緒暫停一下,直到10次之後執行完畢,終止執行緒的執行。
 在上面的程式碼中我們是通過定義全域性變數的方法來指定執行緒暫停間隔,按照這種方法,假如要執行10個執行緒,每個執行緒的暫停間隔不一樣的話,就需要定義10個全域性變數,雖然最終不影響系統的執行效果,但是總覺得不是太爽。
 有沒有比較簡單一點的辦法呢?有!那就是使用帶引數的啟動方法。
 帶引數的啟動方法
 如果要在例項化執行緒時要帶一些引數,就不能用ThreadStart委託作為建構函式的引數來例項化Thread了,而要ParameterizedThreadStart委託,和ThreadStart一樣的是它也是執行緒啟動時要執行的方法,和ThreadStart不同的是,它在例項化時可以用一個帶有一個Object引數的方法作為建構函式的引數,而例項化ThreadStart時所用到的方法是沒有引數的。
 為什麼是Object這樣的引數呢?很簡單,因為在.net中Object是所有型別的基類,用它可以表示Array(陣列)、Interface(介面)、ValueType(值型別,如bool,byte,char,short,int,float,long,double等)、class(類)等.net中的型別。當然,這也意味著如果你要啟動一個執行緒,給它傳遞一個int型別引數時,必須在啟動方法中進行相應的型別轉換。
 下面就是一個例子,在啟動執行緒時指定了執行緒的暫停間隔,程式碼如下:

在這個方法裡,我們在啟動執行緒時順便指定了執行緒的暫停間隔,也就是這句:
 parameterThread.Start(30);
 執行緒啟動時執行的方法是public void ParameterRun(object ms),這個值為30的int型別變數被裝箱成object,所以在方法中還需要將它轉換成int型別,這個可以通過拆箱或者其它辦法解決。
 假如我們要啟動兩個執行緒,每個執行緒的暫停間隔不一樣,啟動程式碼如下:

對上面的程式碼做一點說明,就是執行緒啟動之後,執行緒的例項不必再存在,例如在上面的程式碼中我用的是同一個例項例項化了兩個執行緒,並且這兩個執行緒執行很正常。
 
 繼續探索
 上面解決了一個問題,如果在啟動執行緒時需要引數如何解決,如果針對上面的問題繼續發掘,比如:在啟動執行緒時不但要指定執行緒的暫停間隔,還需要指定迴圈次數(在上面的所有例子中都是執行10次的),這個問題該如何解決呢?
 有兩種辦法可以解決:
 首先可以繼續在ParameterizedThreadStart這裡做文章,因為這裡可以使用一個Object型別的引數,那麼可以通過陣列或者一個類來解決(因為它們都是Object的子類)。我在做某個系統時確實採用陣列處理過這種情況,這樣就要求線上程啟動方法中必須清楚知道陣列中每個引數的用途,不是太方便。
 這裡說說重新定義一個實體類來解決的方法,程式碼如下。

第二種方法和上面方法有些相似,也是需要引入外部類,並且將Thread例項放在引入的類中,這種情況適合於線上程中處理的業務邏輯比較複雜的情況。在前不久處理的一個專案中我用過這種情況,它是用來實現雙向資料傳輸的。
 如果實現上面的效果,程式碼如下:

上面的程式碼的執行效果和前面的程式碼執行效果類似,只不過是將業務處理程式碼放在一個單獨的類MyThreadParameter中,使得MyThreadParameter看起來也像一個Thread,實際上維護的還是其內部的Thread,在一些大型系統中這樣做的好處是便於維護。
 
 總結:在本篇主要講述如何啟動執行緒的問題,在啟動時可能會遇到無需引數、需要多個引數的情況,在這裡講述瞭如何解決這些問題的思路。在.net類庫中雖然存在著龐大的類庫,但是並不是總會有合適的類來解決我們所遇到的問題,但是隻要肯動腦筋總會想到合適的辦法。


更多資訊,請關注本人微信訂閱號:


相關文章