下面將列出一個例子,以說明簡單的線程處理功能。此例子來自于幫助文檔。 using System; using System.Threading;
// Simple threading scenario: Start a static method running // on a second thread. public class ThreadExample { // The ThreadProc method is called when the thread starts. // It loops ten times, writing to the console and yielding // the rest of its time slice each time, and then ends. public static void ThreadProc() { for (int i = 0; i < 10; i++) { Console.WriteLine("ThreadProc: {0}", i); // Yield the rest of the time slice. Thread.Sleep(0); } }
public static void Main() { Console.WriteLine("Main thread: Start a second thread."); // The constructor for the Thread class requires a ThreadStart // delegate that represents the method to be executed on the // thread. C# simplifies the creation of this delegate. Thread t = new Thread(new ThreadStart(ThreadProc)); // Start ThreadProc. On a uniprocessor, the thread does not get // any processor time until the main thread yields. Uncomment // the Thread.Sleep that follows t.Start() to see the difference. t.Start(); //Thread.Sleep(0);
for (int i = 0; i < 4; i++) { Console.WriteLine("Main thread: Do some work."); Thread.Sleep(0); }
Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends."); t.Join(); Console.WriteLine("Main thread: ThreadProc.Join has returned. Press Enter to end program."); Console.ReadLine(); } }
此代碼產(chǎn)生的輸出類似如下內(nèi)容: Main thread: Start a second thread. Main thread: Do some work. ThreadProc: 0 Main thread: Do some work. ThreadProc: 1 Main thread: Do some work. ThreadProc: 2 Main thread: Do some work. ThreadProc: 3 Main thread: Call Join(), to wait until ThreadProc ends. ThreadProc: 4 ThreadProc: 5 ThreadProc: 6 ThreadProc: 7 ThreadProc: 8 ThreadProc: 9 Main thread: ThreadProc.Join has returned. Press Enter to end program.
二、ThreadPool 線程池(ThreadPool)是一種相對較簡單的方法,它適應于一些需要多個線程而又較短任務(如一些常處于阻塞狀態(tài)的線程) ,它的缺點是對創(chuàng)建的線程不能加以控制,也不能設置其優(yōu)先級。由于每個進程只有一個線程池,當然每個應用程序域也只有一個線程池(對線),所以你將發(fā)現(xiàn)ThreadPool類的成員函數(shù)都為static! 當你首次調(diào)用ThreadPool.QueueUserWorkItem、ThreadPool.RegisterWaitForSingleObject等,便會創(chuàng)建線程池實例。下面就線程池當中的兩函數(shù)作一介紹: public static bool QueueUserWorkItem( //調(diào)用成功則返回true WaitCallback callBack,//要創(chuàng)建的線程調(diào)用的委托 object state //傳遞給委托的參數(shù) )//它的另一個重載函數(shù)類似,只是委托不帶參數(shù)而已 此函數(shù)的作用是把要創(chuàng)建的線程排隊到線程池,當線程池的可用線程數(shù)不為零時(線程池有創(chuàng)建線程數(shù)的限制,缺身值為25),便創(chuàng)建此線程,否則就排隊到線程池等到它有可用的線程時才創(chuàng)建。 public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject,// 要注冊的 WaitHandle WaitOrTimerCallback callBack,// 線程調(diào)用的委托 object state,//傳遞給委托的參數(shù) int TimeOut,//超時,單位為毫秒, bool executeOnlyOnce file://是否只執(zhí)行一次 ); public delegate void WaitOrTimerCallback( object state,//也即傳遞給委托的參數(shù) bool timedOut//true表示由于超時調(diào)用,反之則因為waitObject ); 此函數(shù)的作用是創(chuàng)建一個等待線程,一旦調(diào)用此函數(shù)便創(chuàng)建此線程,在參數(shù)waitObject變?yōu)榻K止狀態(tài)或所設定的時間TimeOut到了之前,它都處于“阻塞”狀態(tài),值得注意的一點是此“阻塞”與Thread的WaitSleepJoin狀態(tài)有很大的不同:當某Thread處于WaitSleepJoin狀態(tài)時CPU會定期的喚醒它以輪詢更新狀態(tài)信息,然后再次進入WaitSleepJoin狀態(tài),線程的切換可是很費資源的;而用此函數(shù)創(chuàng)建的線程則不同,在觸發(fā)它運行之前,CPU不會切換到此線程,它既不占用CPU的時間又不浪費線程切換時間,但CPU又如何知道何時運行它?實際上線程池會生成一些輔助線程用來監(jiān)視這些觸發(fā)條件,一旦達到條件便啟動相應的線程,當然這些輔助線程本身也占用時間,但是如果你需創(chuàng)建較多的等待線程時,使用線程池的優(yōu)勢就越加明顯。見下例: static AutoResetEvent ev=new AutoResetEvent(false); public static int Main(string[] args) { ThreadPool.RegisterWaitForSingleObject( ev, new WaitOrTimerCallback(WaitThreadFunc), 4, 2000, false//表示每次完成等待操作后都重置計時器,直到注銷等待 ); ThreadPool.QueueUserWorkItem (new WaitCallback (ThreadFunc),8); Thread.Sleep (10000); return 0; } public static void ThreadFunc(object b) { Console.WriteLine ("the object is {0}",b); for(int i=0;i<2;i++) { Thread.Sleep (1000); ev.Set(); } } public static void WaitThreadFunc(object b,bool t) { Console.WriteLine ("the object is {0},t is {1}",b,t); } 其運行結(jié)果為: the object is 8 the object is 4,t is False the object is 4,t is False the object is 4,t is True the object is 4,t is True the object is 4,t is True 從以上結(jié)果我們可以看出線程ThreadFunc運行了1次,而WaitThreadFunc運行了5次。我們可以從WaitOrTimerCallback中的bool t參數(shù)判斷啟動此線程的原因:t為false,則表示由于waitObject,否則則是由于超時。另外我們也可以通過object b向線程傳遞一些參數(shù)。
3、Timer 它適用于需周期性調(diào)用的方法,它不在創(chuàng)建計時器的線程中運行,它在由系統(tǒng)自動分配的單獨線程中運行。這和Win32中的SetTimer方法類似。它的構(gòu)造為: public Timer( TimerCallback callback,//所需調(diào)用的方法 object state,//傳遞給callback的參數(shù) int dueTime,//多久后開始調(diào)用callback int period//調(diào)用此方法的時間間隔 ); // 如果 dueTime 為0,則 callback 立即執(zhí)行它的首次調(diào)用。如果 dueTime 為 Infinite,則 callback 不調(diào)用它的方法。計時器被禁用,但使用 Change 方法可以重新啟用它。如果 period 為0或 Infinite,并且 dueTime 不為 Infinite,則 callback 調(diào)用它的方法一次。計時器的定期行為被禁用,但使用 Change 方法可以重新啟用它。如果 period 為零 (0) 或 Infinite,并且 dueTime 不為 Infinite,則 callback 調(diào)用它的方法一次。計時器的定期行為被禁用,但使用 Change 方法可以重新啟用它。 在創(chuàng)建計時器之后若想改變它的period和dueTime,我們可以通過調(diào)用Timer的Change方法來改變: public bool Change( int dueTime, int period );//顯然所改變的兩個參數(shù)對應于Timer中的兩參數(shù) public static int Main(string[] args) { Console.WriteLine ("period is 1000"); Timer tm=new Timer (new TimerCallback (TimerCall),3,1000,1000); Thread.Sleep (2000); Console.WriteLine ("period is 500"); tm.Change (0,800); Thread.Sleep (3000); return 0; } public static void TimerCall(object b) { Console.WriteLine ("timercallback; b is {0}",b); } 其運行結(jié)果為: period is 1000 timercallback;b is 3 timercallback;b is 3 period is 500 timercallback;b is 3 timercallback;b is 3 timercallback;b is 3 timercallback;b is 3