線程處理用於使程序能夠執行並發處理,同時執行多個操作。C#中有三種線程的使用方法,BackgroundWorker組件、線程池、自己創建使用線程,接下來分別介紹如何使用。
1.使用BackgroundWorker組件(創建多線程處理程序最可靠方法)
此類管理一個專用於處理指定方法的單獨線程。
添加 DoWork 事件的事件處理程序,為后台操作做好准備,在此事件處理程序中調用耗時的操作。
調用 RunWorkerAsync 函數,開始后台操作。
處理 ProgressChanged 事件,收到進度更新的通知。
處理RunWorkerCompleted 事件,在操作完成時收到通知。
處理 ProgressChanged 和 RunWorkerCompleted 事件的方法可以訪問應用程序的用戶界面,原因是這兩個事件是在調用了 RunWorkerAsync 方法的線程上引發的。 但是,DoWork 事件處理程序無法使用任何用戶界面對象,因為它在后台線程上運行。
2.線程池,是可以用來在后台執行多個任務的線程集合,將任務添加到隊列,然后在創建線程后自動啟動這些任務。線程池通常用於服務器應用程序。 每個傳入請求都將分配給線程池中的一個線程,因此可以異步處理請求,而不會占用主線程,也不會延遲后續請求的處理。一旦池中的某個線程完成任務,它將返回到等待線程隊列中,等待被再次使用,這種重用使應用程序可以避免為每個任務創建新線程的開銷。線程池通常具有最大線程數限制。如果所有線程都繁忙,則額外的任務將放入隊列中,直到有線程可用時才能夠得到處理。
ThreadPool.QueueUserWorkItem(WaitCallback callBack)//將方法排入隊列以便執行。 ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)//將方法排入隊列以便執行,並指定包含該方法所用數據的對象。
3.創建和使用線程
如果需要對應用程序的線程的行為進行更多的控制,則可以自己管理線程。通過聲明類型為 Thread 的變量,並調用為要對新線程執行的過程或方法提供名稱的構造函數,從而創建一個新線程。
System.Threading.Thread newThread = new System.Threading.Thread(AMethod);
線程其他知識點:
1.前台/后台線程
后台線程與前台線程完全一樣,只是后台線程不會阻止進程終止。前台線程的運行時間不限定,而后台線程則在最后一個前台線程停止時立即停止。 可以使用 IsBackground 屬性確定或更改線程的后台狀態。默認情況下,主線程、通過Thread類構造函數創建的線程在前台執行,線程池線程、從非托管代碼進入托管環境的線程在后台執行。
2.線程的參數和返回值
為線程提供參數:將目標方法包裹在類中,並為該類定義字段,這些字段將被用作新線程的參數。
從線程獲取返回值:使用BackgroundWorker 組件來管理線程,在任務完成時引發RunWorkerCompleted 事件,然后用事件處理程序處理結果。
3.線程同步
在應用程序中使用多個線程,必須協調對資源(如文件句柄、網絡連接和內存)的訪問。C#中的線程同步方法有鎖、監視器、同步事件和等待句柄、Mutex對象、Interlocked類、ReaderWriter鎖。
鎖:lock 關鍵字將語句塊標記為臨界區,方法是獲取給定對象的互斥鎖,執行語句,然后釋放該鎖。
監視器:與lock關鍵字類似,防止多個線程同時執行代碼塊,但是lock更簡潔、更安全。
同步事件和等待句柄:同步事件有終止、非終止兩個狀態的對象,用來激活和掛起線程,讓線程等待一個非終止同步事件可以將線程掛起,將事件狀態變為終止可以激活線程。如果線程嘗試等待已經終止的事件,則線程繼續執行,不會受到延遲。同步事件有AutoResetEvent和ManualResetEvent兩種,只要AutoResetEvent 激活線程,其狀態自動從終止變為非終止,ManualResetEvent 允許它的終止狀態激活任意個線程,並只有調用其Reset方法時才還原到非終止狀態。
通過調用WaitOne、WaitAny、WaitAll等待方法使線程等待事件,當調用事件的Set方法,事件變為終止狀態。
using System; using System.Threading; class ThreadingExample { static AutoResetEvent autoEvent; static void DoWork() { Console.WriteLine(" worker thread started, now waiting on event..."); autoEvent.WaitOne(); Console.WriteLine(" worker thread reactivated, now exiting..."); } static void Main() { autoEvent = new AutoResetEvent(false); Console.WriteLine("main thread starting worker thread..."); Thread t = new Thread(DoWork); t.Start(); Console.WriteLine("main thread sleeping for 1 second..."); Thread.Sleep(1000); Console.WriteLine("main thread signaling worker thread..."); autoEvent.Set();
Console.ReadLine(); } }
執行結果
Mutex 對象,與監視器類似。
Interlock類,使用 Interlocked 類的方法來避免在多個線程嘗試同時更新或比較同一個值時可能出現的問題。使用這個類的方法可以安全地遞增、遞減、交換和比較任何線程中的值。
ReadWriter鎖,只在寫入數據時鎖定資源,在不更新數據時允許多個客戶端同時讀取數據。 ReaderWriterLock 類在線程修改資源時將強制其獨占訪問資源,但在讀取資源時則允許非獨占訪問。ReaderWriterLock 類定義支持單個寫線程和多個讀線程的鎖。
死鎖,多線程應用程序始終存在deadlock 的危險,在編碼前多考慮,避免死鎖。
4.線程計時器。System.Threading.Timer 類可用於定期在單獨的線程上運行任務,創建實例后計時器開始啟動。