線程 被定義為程序的執(zhí)行路徑。每個線程都定義了一個獨特的控制流。如果您的應(yīng)用程序涉及到復(fù)雜的和耗時的操作,那么設(shè)置不同的線程執(zhí)行路徑往往是有益的,每個線程執(zhí)行特定的工作。
線程是輕量級進程。一個使用線程的常見示例是現(xiàn)代操作系統(tǒng)中并行編程的實現(xiàn)。使用線程節(jié)省了 CPU 周期的浪費,同時提高了應(yīng)用程序的效率。
到目前為止我們編寫的程序是一個單線程作為應(yīng)用程序的運行示例的單一的過程運行的。但是,這樣子應(yīng)用程序同時只能執(zhí)行一個任務(wù)。為了同時執(zhí)行多個任務(wù),它可以被劃分為更小的線程。
線程生命周期開始于 System.Threading.Thread 類的對象被創(chuàng)建時,結(jié)束于線程被終止或完成執(zhí)行時。
下面列出了線程生命周期中的各種狀態(tài):
未啟動狀態(tài):當(dāng)線程示例被創(chuàng)建但 Start 方法未被調(diào)用時的狀況。
就緒狀態(tài):當(dāng)線程準(zhǔn)備好運行并等待 CPU 周期時的狀況。
不可運行狀態(tài):下面的幾種情況下線程是不可運行的:
已經(jīng)調(diào)用 Sleep 方法
已經(jīng)調(diào)用 Wait 方法
通過 I/O 操作阻塞
死亡狀態(tài):當(dāng)線程已完成執(zhí)行或已中止時的狀況。
在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創(chuàng)建并訪問多線程應(yīng)用程序中的單個線程。進程中第一個被執(zhí)行的線程稱為主線程。
當(dāng) C# 程序開始執(zhí)行時,主線程自動創(chuàng)建。使用 Thread 類創(chuàng)建的線程被主線程的子線程調(diào)用。您可以使用 Thread 類的 CurrentThread 屬性訪問線程。
下面的程序演示了主線程的執(zhí)行:
using System; using System.Threading; namespace MultithreadingApplication { class MainThreadProgram { static void Main(string[] args) { Thread th = Thread.CurrentThread; th.Name = "MainThread"; Console.WriteLine("This is {0}", th.Name); Console.ReadKey(); } } }
當(dāng)上面的代碼被編譯和執(zhí)行時,它會產(chǎn)生下列結(jié)果:
This is MainThread
下表列出了 Thread 類的一些常用的 屬性:
屬性 | 描述 |
---|---|
CurrentContext | 獲取線程正在其中執(zhí)行的當(dāng)前上下文。 |
CurrentCulture | 獲取或設(shè)置當(dāng)前線程的區(qū)域性。 |
CurrentPrincipal | 獲取或設(shè)置線程的當(dāng)前負責(zé)人(對基于角色的安全性而言)。 |
CurrentThread | 獲取當(dāng)前正在運行的線程。 |
CurrentUICulture | 獲取或設(shè)置資源管理器使用的當(dāng)前區(qū)域性以便在運行時查找區(qū)域性特定的資源。 |
ExecutionContext | 獲取一個 ExecutionContext 對象,該對象包含有關(guān)當(dāng)前線程的各種上下文的信息。 |
IsAlive | 獲取一個值,該值指示當(dāng)前線程的執(zhí)行狀態(tài)。 |
IsBackground | 獲取或設(shè)置一個值,該值指示某個線程是否為后臺線程。 |
IsThreadPoolThread | 獲取一個值,該值指示線程是否屬于托管線程池。 |
ManagedThreadId | 獲取當(dāng)前托管線程的唯一標(biāo)識符。 |
Name | 獲取或設(shè)置線程的名稱。 |
Priority | 獲取或設(shè)置一個值,該值指示線程的調(diào)度優(yōu)先級。 |
ThreadState | 獲取一個值,該值包含當(dāng)前線程的狀態(tài)。 |
下表列出了 Thread 類的一些常用的 方法:
序號 | 方法名 & 描述 |
---|---|
1 | public void Abort() 在調(diào)用此方法的線程上引發(fā) ThreadAbortException,以開始終止此線程的過程。調(diào)用此方法通常會終止線程。 |
2 | public static LocalDataStoreSlot AllocateDataSlot() 在所有的線程上分配未命名的數(shù)據(jù)槽。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標(biāo)記的字段。 |
3 | public static LocalDataStoreSlot AllocateNamedDataSlot(
string name) 在所有線程上分配已命名的數(shù)據(jù)槽。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標(biāo)記的字段。 |
4 | public static void BeginCriticalRegion() 通知主機執(zhí)行將要進入一個代碼區(qū)域,在該代碼區(qū)域內(nèi)線程中止或未經(jīng)處理的異常的影響可能會危害應(yīng)用程序域中的其他任務(wù)。 |
5 | public static void BeginThreadAffinity() 通知主機托管代碼將要執(zhí)行依賴于當(dāng)前物理操作系統(tǒng)線程的標(biāo)識的指令。 |
6 | public static void EndCriticalRegion() 通知主機執(zhí)行將要進入一個代碼區(qū)域,在該代碼區(qū)域內(nèi)線程中止或未經(jīng)處理的異常僅影響當(dāng)前任務(wù)。 |
7 | public static void EndThreadAffinity() 通知主機托管代碼已執(zhí)行完依賴于當(dāng)前物理操作系統(tǒng)線程的標(biāo)識的指令。 |
8 | public static void FreeNamedDataSlot(string name) 為進程中的所有線程消除名稱與槽之間的關(guān)聯(lián)。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標(biāo)記的字段。 |
9 | public static Object GetData(
LocalDataStoreSlot slot
) 在當(dāng)前線程的當(dāng)前域中從當(dāng)前線程上指定的槽中檢索值。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標(biāo)記的字段。 |
10 | public static AppDomain GetDomain() 返回當(dāng)前線程正在其中運行的當(dāng)前域。 |
11 | public static AppDomain GetDomainID() 返回唯一的應(yīng)用程序域標(biāo)識符。 |
12 | public static LocalDataStoreSlot GetNamedDataSlot(
string name
) 查找已命名的數(shù)據(jù)槽。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標(biāo)記的字段。 |
13 | public void Interrupt() 中斷處于 WaitSleepJoin 線程狀態(tài)的線程。 |
14 | public void Join() 在繼續(xù)執(zhí)行標(biāo)準(zhǔn)的 COM 和 SendMessage 消息泵處理期間,阻塞調(diào)用線程,直到某個線程終止為止。此方法有不同的重載形式。 |
15 | public static void MemoryBarrier() 按如下方式同步內(nèi)存存?。簣?zhí)行當(dāng)前線程的處理器在對指令重新排序時,不能采用先執(zhí)行 MemoryBarrier 調(diào)用之后的內(nèi)存存取,再執(zhí)行 MemoryBarrier 調(diào)用之前的內(nèi)存存取的方式。 |
16 | public static void ResetAbort() 取消為當(dāng)前線程請求的 Abort。 |
17 | public static void SetData(
LocalDataStoreSlot slot,
Object data
) 在當(dāng)前正在運行的線程上為此線程的當(dāng)前域在指定槽中設(shè)置數(shù)據(jù)。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標(biāo)記的字段。 |
18 | public void Start() 開始一個線程。 |
19 | public static void Sleep(
int millisecondsTimeout
) 讓線程暫停一段時間。 |
20 | public static void SpinWait(
int iterations
) 導(dǎo)致線程等待由 iterations 參數(shù)定義的時間量。 |
21 | public static byte VolatileRead(
ref byte address
) public static double VolatileRead( ref double address ) public static int VolatileRead( ref int address ) public static Object VolatileRead( ref Object address ) 讀取字段值。無論處理器的數(shù)目或處理器緩存的狀態(tài)如何,該值都是由計算機的任何處理器寫入的最新值。此方法有不同的重載形式。這里只給出了一些形式。 |
22 | public static void VolatileWrite(
ref byte address,
byte value
) public static void VolatileWrite( ref double address, double value ) public static void VolatileWrite( ref int address, int value ) public static void VolatileWrite( ref Object address, Object value ) 立即向字段寫入一個值,以使該值對計算機中的所有處理器都可見。此方法有不同的重載形式。這里只給出了一些形式。 |
23 | public static bool Yield() 導(dǎo)致調(diào)用線程執(zhí)行準(zhǔn)備好在當(dāng)前處理器上運行的另一個線程。由操作系統(tǒng)選擇要執(zhí)行的線程。 |
線程是通過擴展 Thread 類創(chuàng)建的。擴展的 Thread 類調(diào)用 Start() 方法來開始子線程的執(zhí)行。
下面的程序演示了這個概念:
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { Console.WriteLine("Child thread starts"); } static void Main(string[] args) { ThreadStart childref = new ThreadStart(CallToChildThread); Console.WriteLine("In Main: Creating the Child thread"); Thread childThread = new Thread(childref); childThread.Start(); Console.ReadKey(); } } }
當(dāng)上面的代碼被編譯和執(zhí)行時,它會產(chǎn)生下列結(jié)果:
In Main: Creating the Child thread Child thread starts
Thread 類提供了各種管理線程的方法。
下面的示例演示了 sleep() 方法的使用,用于在一個特定的時間暫停線程。
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { Console.WriteLine("Child thread starts"); // 線程暫停 5000 毫秒 int sleepfor = 5000; Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000); Thread.Sleep(sleepfor); Console.WriteLine("Child thread resumes"); } static void Main(string[] args) { ThreadStart childref = new ThreadStart(CallToChildThread); Console.WriteLine("In Main: Creating the Child thread"); Thread childThread = new Thread(childref); childThread.Start(); Console.ReadKey(); } } }
當(dāng)上面的代碼被編譯和執(zhí)行時,它會產(chǎn)生下列結(jié)果:
In Main: Creating the Child thread Child thread starts Child Thread Paused for 5 seconds Child thread resumes
Abort() 方法用于銷毀線程。
通過拋出 threadabortexception 在運行時中止線程。這個異常不能被捕獲,如果有 finally 塊,控制會被送至 finally 塊。
下面的程序說明了這點:
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { try { Console.WriteLine("Child thread starts"); // 計數(shù)到 10 for (int counter = 0; counter <= 10; counter++) { Thread.Sleep(500); Console.WriteLine(counter); } Console.WriteLine("Child Thread Completed"); } catch (ThreadAbortException e) { Console.WriteLine("Thread Abort Exception"); } finally { Console.WriteLine("Couldn't catch the Thread Exception"); } } static void Main(string[] args) { ThreadStart childref = new ThreadStart(CallToChildThread); Console.WriteLine("In Main: Creating the Child thread"); Thread childThread = new Thread(childref); childThread.Start(); // 停止主線程一段時間 Thread.Sleep(2000); // 現(xiàn)在中止子線程 Console.WriteLine("In Main: Aborting the Child thread"); childThread.Abort(); Console.ReadKey(); } } }
當(dāng)上面的代碼被編譯和執(zhí)行時,它會產(chǎn)生下列結(jié)果:
In Main: Creating the Child thread Child thread starts 0 1 2 In Main: Aborting the Child thread Thread Abort Exception Couldn't catch the Thread Exception