問題一,線程的基本操作,例如:暫停、繼續、停止等
我不建議使用Thread類提供的Suspend、Resume以及Abort這三個方法,前兩個有問題,好像在VS05已經屏蔽這兩個方法;對於Abort來說,除了資源沒有得到及時釋放外,有時候會出現異常。如何做呢,通過設置開關變量來完成
問題二,如何向線程傳遞參數或者從中得到其返回值;
我不建議使用靜態成員來完成,僅僅為了線程而破壞類的封裝有些得不償失。那如何做呢,通過創建單獨的線程類來完成

//委托 public delegate double weiTuo(double a, double b); weiTuo w; private void btn_Begin_Click(object sender, EventArgs e) { //Thread th_thread = new Thread(); w = new weiTuo(getCount); //異步調用中的參數和返回值 AsyncCallback callback = new AsyncCallback(AsyncCallbackImpl); w.BeginInvoke(1, 2, callback, null); } //線程調用的方法 double getCount(double a, double b) { return a + b; } /// <summary> /// 線程完成之后回調的函數 /// </summary> /// <param name="ar"></param> public void AsyncCallbackImpl(IAsyncResult ar) { //獲取執行完后的返回值 double re = w.EndInvoke(ar); MessageBox.Show(" " + ar.AsyncState); }
當線程的ThreadState==ThreadState.Stop時,一般就說明線程完成了工作,這時結果就可用了,如果不是這個狀態,就繼續執行別的工作,或者等待一會,然后再嘗試.倘若需要等有多個子線程需的返回,並且需要用他們的結果來進行進異步計算,那就叫做線程同步了,下面我們介紹另外一種我比較推薦的方法,能夠自定義參數個數,並且返回數據,而且使用起來也相對方便
使用委托的異步調用方法和回調
首先我們要把需要異步調用的方法定義為一個委托,然后利用BeginInvoke來異步調用,BeginInvoke的第一個參數就是直徑,第二個是當線程執行完畢后的調用的方法
問題三,如何使線程所占用的CPU不要老是百分之百
造成這個原因是由於線程中進行不間斷的循環操作,從而使CPU完全被子線程占有。那么處理此類問題,其實很簡單,在適當的位置調用Thread.Sleep(20)來釋放所占有CPU資源,不要小看這20毫秒的睡眠,它的作用可是巨大的,可以使其他線程得到CPU資源,從而使你的CPU使用效率降下來。
對於上面三個問題用一個例子呈現給大家:

namespace ThreadTemplate { using System; using System.Threading; using System.IO; /// <summary> /// Summary description for clsSubThread. /// </summary> public class clsSubThread:IDisposable { private Thread thdSubThread = null; private Mutex mUnique = new Mutex(); private bool blnIsStopped; private bool blnSuspended; private bool blnStarted; private int nStartNum; public bool IsStopped { get{ return blnIsStopped; } } public bool IsSuspended { get{ return blnSuspended; } } public int ReturnValue { get{ return nStartNum;} } public clsSubThread( int StartNum ) { // // TODO: Add constructor logic here // blnIsStopped = true; blnSuspended = false; blnStarted = false; nStartNum = StartNum; } /// <summary> /// Start sub-thread /// </summary> public void Start() { if( !blnStarted ) { thdSubThread = new Thread( new ThreadStart( SubThread ) ); blnIsStopped = false; blnStarted = true; thdSubThread.Start(); } } /// <summary> /// Thread entry function /// </summary> private void SubThread() { do { // Wait for resume-command if got suspend-command here mUnique.WaitOne(); mUnique.ReleaseMutex(); nStartNum++; Thread.Sleep(1000); // Release CPU here }while( blnIsStopped == false ); } /// <summary> /// Suspend sub-thread /// </summary> public void Suspend() { if( blnStarted && !blnSuspended ) { blnSuspended = true; mUnique.WaitOne(); } } /// <summary> /// Resume sub-thread /// </summary> public void Resume() { if( blnStarted && blnSuspended ) { blnSuspended = false; mUnique.ReleaseMutex(); } } /// <summary> /// Stop sub-thread /// </summary> public void Stop() { if( blnStarted ) { if( blnSuspended ) Resume(); blnStarted = false; blnIsStopped = true; thdSubThread.Join(); } } #region IDisposable Members /// <summary> /// Class resources dispose here /// </summary> public void Dispose() { // TODO: Add clsSubThread.Dispose implementation Stop();//Stop thread first GC.SuppressFinalize( this ); } #endregion } } 那么對於調用呢,就非常簡單了,如下: // Create new sub-thread object with parameters clsSubThread mySubThread = new clsSubThread( 5 ); mySubThread.Start();//Start thread Thread.Sleep( 2000 ); mySubThread.Suspend();//Suspend thread Thread.Sleep( 2000 ); mySubThread.Resume();//Resume thread Thread.Sleep( 2000 ); mySubThread.Stop();//Stop thread //Get thread's return value Debug.WriteLine( mySubThread.ReturnValue ); //Release sub-thread object mySubThread.Dispose();
在回過頭來看看前面所說的三個問題。
對於問題一來說,首先需要局部成員的支持,那么

private Mutex mUnique = new Mutex(); private bool blnIsStopped; private bool blnSuspended; private bool blnStarted;
光看成員名稱,估計大家都已經猜出其代表的意思。接下來需要修改線程入口函數,要是這些開關變量能發揮作用,那么看看SubThread這個函數。

/// <summary> /// Thread entry function /// </summary> private void SubThread() { do { // Wait for resume-command if got suspend-command here mUnique.WaitOne(); mUnique.ReleaseMutex(); nStartNum++; Thread.Sleep(1000); }while( blnIsStopped == false ); }
函數比較簡單,不到十句,可能對於“blnIsStopped == false”這個判斷來說,大家還比較好理解,這是一個普通的判斷,如果當前Stop開關打開了,就停止循環;否則一直循環。
大家比較迷惑的可能是如下這兩句:
mUnique.WaitOne();
mUnique.ReleaseMutex();
這兩句的目的是為了使線程在Suspend操作的時候能發揮效果,為了解釋這兩句,需要結合Suspend和Resume這兩個方法,它倆的代碼如下。

/// <summary> /// Suspend sub-thread /// </summary> public void Suspend() { if( blnStarted && !blnSuspended ) { blnSuspended = true; mUnique.WaitOne(); } } /// <summary> /// Resume sub-thread /// </summary> public void Resume() { if( blnStarted && blnSuspended ) { blnSuspended = false; mUnique.ReleaseMutex(); } }
為了更好地說明,還需要先簡單說說Mutex類型。對於此類型對象,當調用對象的WaitOne之后,如果此時沒有其他線程對它使用的時候,就立刻獲得信號量,繼續執行代碼;當再調用ReleaseMutex之前,如果再調用對象的WaitOne方法,就會一直等待,直到獲得信號量的調用ReleaseMutex來進行釋放。這就好比衛生間的使用,如果沒有人使用則可以直接使用,否則只有等待。
明白了這一點后,再來解釋這兩句所能出現的現象。
mUnique.WaitOne();
mUnique.ReleaseMutex();
當在線程函數中,執行到“mUnique.WaitOne();”這一句的時候,如果此時外界沒有發送Suspend消息,也就是信號量沒有被占用,那么這一句可以立刻返回。那么為什么要緊接着釋放呢,因為不能總占着信號量,立即釋放信號量是避免在發送Suspend命令的時候出現等待;如果此時外界已經發送了Suspend消息,也就是說信號量已經被占用,此時“mUnique.WaitOne();”不能立刻返回,需要等到信號量被釋放才能繼續進行,也就是需要調用Resume的時候,“mUnique.WaitOne();”才能獲得信號量進行繼續執行。這樣才能達到真正意義上的Suspend和Resume。
現在再來分析一下問題二,其實例子比較明顯,是通過構造函數和屬性來完成參數和返回值,這一點我也不多說了。如果線程參數比較多的話,可以考慮屬性來完成,類似於返回值。
問題三,我就更不用多說了。有人說了,如果子線程中的循環不能睡眠怎么辦,因為睡眠的話,有時會造成數據丟失,這方面的可以借鑒前面Suspend的做法,
為什么不能直接在子線程中操縱UI呢。原因在於子線程和UI線程屬於不同的上下文,換句比較通俗的話說,就好比兩個人在不同的房間里一樣,那么要你直接操作另一個房間里的東西,恐怕不行罷,那么對於子線程來說也一樣,不能直接操作UI線程中的對象。
那么如何在子線程中操縱UI線程中的對象呢,.Net提供了Invoke和BeginInvoke這兩種方法。簡單地說,就是子線程發消息讓UI線程來完成相應的操作
這兩個方法有什么區別,這在我以前的文章已經說過了,Invoke需要等到所調函數的返回,而BeginInvoke則不需要。
用這兩個方法需要注意的,有如下三點:
第一個是由於Invoke和BeginInvoke屬於Control類型的成員方法,因此調用的時候,需要得到Control類型的對象才能觸發,也就是說你要觸發窗體做什么操作或者窗體上某個控件做什么操作,需要把窗體對象或者控件對象傳遞到線程中。
第二個,對於Invoke和BeginInvoke接受的參數屬於一個delegate類型,我在以前的文章中使用的是MethodInvoker,這是.Net自帶的一個delegate類型,而並不意味着在使用Invoke或者BeginInvoke的時候只能用它。參看我給的第二篇文章(《如何彈出一個模式窗口來顯示進度條》),會有很多不同的delegate定義。
最后一個,使用Invoke和BeginInvoke有個需要注意的,就是當子線程在Form_Load開啟的時候,會遇到異常,這是因為觸發Invoke的對象還沒有完全初始化完畢。處理此類問題,在開啟線程之前顯式的調用“this.Show();”,來使窗體顯示在線程開啟之前。如果此時只是開啟線程來初始化顯示數據,那我建議你不要使用子線程,用Splash窗體的效果可能更好。
150279198---加QQ群聊--大神勿擾。--菜鳥營