C#綜合揭秘——細說多線程(上)

來源:互聯網
上載者:User

引言

本文主要從線程的基礎用法,CLR線程池當中工作者線程與I/O線程的開發,並行操作PLINQ等多個方面介紹多線程的開發。
其中委託的BeginInvoke方法以及回呼函數最為常用。
而 I/O線程可能容易遭到大家的忽略,其實在開發多線程系統,更應該多留意I/O線程的操作。特別是在ASP.NET開發當中,可能更多人只會留意在用戶端使用Ajax或者在伺服器端使用UpdatePanel。其實合理使用I/O線程在通訊項目或檔案下載時,能儘可能地減少IIS的壓力。
並行編程是Framework4.0中極力推廣的非同步作業方式,更值得更深入地學習。
希望本篇文章能對各位的學習研究有所協助,當中有所錯漏的地方敬請點評。

 

 

目錄

一、線程的定義

二、線程的基礎知識

三、以ThreadStart方式實現多線程

四、CLR線程池的工作者線程

五、CLR線程池的I/O線程

六、非同步 SqlCommand

七、並行編程與PLINQ

八、計時器與鎖

 

 

 

 

一、線程的定義

 1. 1 進程、應用程式定義域與線程的關係

進程(Process)是Windows系統中的一個基本概念,它包含著一個運行程式所需要的資源。進程之間是相對獨立的,一個進程無法訪問另一個進程的資料(除非利用分散式運算方式),一個進程啟動並執行失敗也不會影響其他進程的運行,Windows系統就是利用進程把工作劃分為多個獨立的地區的。進程可以理解為一個程式的基本邊界。

應用程式定義域(AppDomain)是一個程式啟動並執行邏輯地區,它可以視為一個輕量級的進程,.NET的程式集正是在應用程式定義域中啟動並執行,一個進程可以包含有多個應用程式定義域,一個應用程式定義域也可以包含多個程式集。在一個應用程式定義域中包含了一個或多個上下文context,使用上下文CLR就能夠把某些特殊對象的狀態放置在不同容器當中。

線程(Thread)是進程中的基本執行單元,在進程入口執行的第一個線程被視為這個進程的主線程。在.NET應用程式中,都是以Main()方法作為入口的,當調用此方法時系統就會自動建立一個主線程。線程主要是由CPU寄存器、調用棧和執行緒區域儲存空間(Thread Local Storage,TLS)組成的。CPU寄存器主要記錄當前所執行線程的狀態,調用棧主要用於維護線程所調用到的記憶體與資料,TLS主要用於存放線程的狀態資訊。

進程、應用程式定義域、線程的關係如下圖,一個進程內可以包括多個應用程式定義域,也有包括多個線程,線程也可以穿梭於多個應用程式定義域當中。但在同一個時刻,線程只會處於一個應用程式定義域內。

 

 
由於本文是以介紹多線程技術為主題,對進程、應用程式定義域的介紹就到此為止。關於進程、線程、應用程式定義域的技術,在“C#綜合揭秘——細說進程、應用程式定義域與上下文”會有詳細介紹。

 

1.2 多線程

在單CPU系統的一個單位時間(time slice)內,CPU只能運行單個線程,運行順序取決於線程的優先順序別。如果在單位時間內線程未能完成執行,系統就會把線程的狀態資訊儲存到線程的本機存放區器(TLS) 中,以便下次執行時恢複執行。而多線程只是系統帶來的一個假像,它在多個單位時間內進行多個線程的切換。因為切換頻密而且單位時間非常短暫,所以多線程可被視作同時運行。

適當使用多線程能提高系統的效能,比如:在系統請求大容量的資料時使用多線程,把資料輸出工作交給非同步線程,使主線程保持其穩定性去處理其他問題。但需要注意一點,因為CPU需要花費不少的時間線上程的切換上,所以過多地使用多線程反而會導致效能的下降。

 

返回目錄

二、線程的基礎知識

2.1 System.Threading.Thread類

System.Threading.Thread是用於控制線程的基礎類,通過Thread可以控制當前應用程式定義域中線程的建立、掛起、停止、銷毀。

它包括以下常用公用屬性:

屬性名稱 說明
CurrentContext 擷取線程正在其中執行的當前上下文。
CurrentThread 擷取當前正在啟動並執行線程。
ExecutionContext 擷取一個 ExecutionContext 對象,該對象包含有關當前線程的各種內容相關的資訊。
IsAlive 擷取一個值,該值指示當前線程的執行狀態。
IsBackground 擷取或設定一個值,該值指示某個線程是否為後台線程。
IsThreadPoolThread 擷取一個值,該值指示線程是否屬於託管線程池。
ManagedThreadId 擷取當前託管線程的唯一識別碼。
Name 擷取或設定線程的名稱。
Priority 擷取或設定一個值,該值指示線程的調度優先順序。
ThreadState 擷取一個值,該值包含當前線程的狀態。

 

2.1.1 線程的標識符

ManagedThreadId是確認線程的唯一識別碼,程式在大部分情況下都是通過Thread.ManagedThreadId來辨別線程的。而Name是一個可變值,在預設時候,Name為一個空值 Null,開發人員可以通過程式設定線程的名稱,但這隻是一個協助工具功能。

 

2.1.2 線程的優先順序別

.NET為線程設定了Priority屬性來定義線程執行的優先順序別,裡麵包含5個選項,其中Normal是預設值。除非系統有特殊要求,否則不應該隨便設定線程的優先順序別。

成員名稱 說明
Lowest 可以將 Thread 安排在具有任何其他優先順序的線程之後。
BelowNormal 可以將 Thread 安排在具有 Normal 優先順序的線程之後,在具有 Lowest 優先順序的線程之前。
Normal 預設選擇。可以將 Thread 安排在具有 AboveNormal 優先順序的線程之後,在具有 BelowNormal優先順序的線程之前。
AboveNormal 可以將 Thread 安排在具有 Highest 優先順序的線程之後,在具有 Normal 優先順序的線程之前。
Highest 可以將 Thread 安排在具有任何其他優先順序的線程之前。

 

2.1.3 線程的狀態

通過ThreadState可以檢測線程是處於Unstarted、Sleeping、Running 等等狀態,它比 IsAlive 屬效能提供更多的特定資訊。

前面說過,一個應用程式定義域中可能包括多個上下文,而通過CurrentContext可以擷取線程當前的上下文。

CurrentThread是最常用的一個屬性,它是用於擷取當前啟動並執行線程。

 

2.1.4 System.Threading.Thread的方法

Thread 中包括了多個方法來控制線程的建立、掛起、停止、銷毀,以後來的例子中會經常使用。

方法名稱 說明
Abort() 終止本線程。
GetDomain() 返回當前線程正在其中啟動並執行當前域。
GetDomainId() 返回當前線程正在其中啟動並執行當前域Id。
Interrupt() 中斷處於 WaitSleepJoin 線程狀態的線程。
Join() 已重載。 阻塞調用線程,直到某個線程終止時為止。
Resume() 繼續運行已掛起的線程。
Start() 執行本線程。
Suspend() 掛起當前線程,如果當前線程已屬於掛起狀態則此不起作用
Sleep() 把正在啟動並執行線程掛起一段時間。

 

2.1.5 開發執行個體

以下這個例子,就是通過Thread顯示當前線程資訊

 1         static void Main(string[] args) 2         { 3             Thread thread = Thread.CurrentThread; 4             thread.Name = "Main Thread"; 5             string threadMessage = string.Format("Thread ID:{0}\n    Current AppDomainId:{1}\n    "+ 6                 "Current ContextId:{2}\n    Thread Name:{3}\n    "+ 7                 "Thread State:{4}\n    Thread Priority:{5}\n", 8                 thread.ManagedThreadId, Thread.GetDomainID(), Thread.CurrentContext.ContextID, 9                 thread.Name, thread.ThreadState, thread.Priority);10             Console.WriteLine(threadMessage);11             Console.ReadKey();12         }

 

運行結果

 

2.2  System.Threading 命名空間

在System.Threading命名空間內提供多個方法來構建多線程應用程式,其中ThreadPool與Thread是多線程開發中最常用到的,在.NET中專門設定了一個CLR線程池專門用於管理線程的運行,這個CLR線程池正是通過ThreadPool類來管理。而Thread是管理線程的最直接方式,下面幾節將詳細介紹有關內容。

類     說明
AutoResetEvent 通知正在等待的線程已發生事件。無法繼承此類。
ExecutionContext 管理當前線程的執行內容。無法繼承此類。
Interlocked 為多個線程共用的變數提供原子操作。
Monitor 提供同步對對象的訪問的機制。
Mutex 一個同步基元,也可用於進程間同步。
Thread 建立並控制線程,設定其優先順序並擷取其狀態。
ThreadAbortException 在對 Abort 方法進行調用時引發的異常。無法繼承此類。
ThreadPool 提供一個線程池,該線程池可用於發送工作項目、處理非同步 I/O、代表其他線程等待以及處理計時器。
Timeout 包含用於指定無限長的時間的常數。無法繼承此類。
Timer 提供以指定的時間間隔執行方法的機制。無法繼承此類。
WaitHandle 封裝等待對共用資源的獨佔訪問的作業系統特定的對象。


在System.Threading中的包含了下表中的多個常用委託,其中ThreadStart、ParameterizedThreadStart是最常用到的委託。
由ThreadStart產生的線程是最直接的方式,但由ThreadStart所產生並不受線程池管理。
而ParameterizedThreadStart是為非同步觸發帶參數的方法而設的,在下一節將為大家逐一細說。

委託 說明
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.