線程的定義是程序的執(zhí)行路徑。每個(gè)線程都定義了一個(gè)獨(dú)特的控制流,如果應(yīng)用程序涉及到復(fù)雜且耗時(shí)的操作,那么設(shè)置不同的線程執(zhí)行路徑會(huì)非常有好處,因?yàn)槊總€(gè)線程會(huì)被指定于執(zhí)行特定的工作。
線程實(shí)際上是輕量級(jí)進(jìn)程。一個(gè)常見(jiàn)的使用線程的實(shí)例是現(xiàn)代操作系統(tǒng)中的并行編程。使用線程不僅有效地減少了 CPU 周期的浪費(fèi),同時(shí)還提高了應(yīng)用程序的運(yùn)行效率。
到目前為止我們所編寫的程序都是以一個(gè)單線程作為應(yīng)用程序的運(yùn)行的,其運(yùn)行過(guò)程均為單一的。但是,在這種情況下,應(yīng)用程序在同一時(shí)間只能執(zhí)行一個(gè)任務(wù)。為了使應(yīng)用程序可以同時(shí)執(zhí)行多個(gè)任務(wù),需要將其被劃分為多個(gè)更小的線程。
線程的生命周期開(kāi)始于對(duì)象的 System.Threading.Thread 類創(chuàng)建時(shí),結(jié)束于線程被終止或是完成執(zhí)行時(shí)。下列各項(xiàng)為線程在生命周期中的各種狀態(tài):
在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創(chuàng)建并訪問(wèn)多線程應(yīng)用程序中的單個(gè)線程。進(jìn)程中第一個(gè)被執(zhí)行的線程稱為主線程。
當(dāng) C# 程序開(kāi)始執(zhí)行時(shí),會(huì)自動(dòng)創(chuàng)建主線程。使用 Thread 類創(chuàng)建的線程被主線程的子線程調(diào)用。通過(guò) Thread 類的 CurrentThread 屬性可以訪問(wèn)線程。
下面的程序演示了主線程的執(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();
}
}
}
編譯執(zhí)行上述代碼,得到如下結(jié)果:
This is MainThread
下表為 Thread 類一些常用的屬性:
屬性 | 描述 |
---|---|
CurrentContext | 獲取線程當(dāng)前正在執(zhí)行的線程的上下文。 |
CurrentCulture | 獲取或設(shè)置當(dāng)前線程的區(qū)域性 |
CurrentPrinciple | 獲取或設(shè)置線程的當(dāng)前責(zé)任人(針對(duì)基于角色的安全性) |
CurrentThread | 獲取當(dāng)前正在運(yùn)行的線程 |
CurrentUICulture | 獲取或設(shè)置資源管理器當(dāng)前所使用的區(qū)域性,便于在運(yùn)行時(shí)查找區(qū)域性特定的資源 |
ExecutionContext | 獲取一個(gè) ExcutionContext 對(duì)象,該對(duì)象包含有關(guān)當(dāng)前線程的各種上下文信息。 |
IsAlive | 獲取一個(gè)值,指示當(dāng)前線程的執(zhí)行狀態(tài)。 |
IsBackground | 獲取或設(shè)置一個(gè)值,指示線程是否為后臺(tái)線程。 |
IsThreadPoolThread | 獲取或設(shè)置一個(gè)值,指示線程是否屬于托管線程池。 |
ManagedThreadId | 獲取當(dāng)前托管線程的唯一標(biāo)識(shí)符 |
Name | 獲取或設(shè)置線程的名稱。 |
Priority | 獲取或設(shè)置一個(gè)值,指示線程的調(diào)度優(yōu)先級(jí) |
ThreadState | 獲取一個(gè)值,指示當(dāng)前線程的狀態(tài)。 |
下表為 Thread 類一些常用的方法:
序號(hào) | 方法名和描述 |
---|---|
1 | public void Abort() 在調(diào)用此方法的線程上引發(fā) ThreadAbortException,則觸發(fā)終止此線程的操作。調(diào)用此方法通常會(huì)終止線程。 |
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() 通知主機(jī)將要進(jìn)入一個(gè)代碼區(qū)域,若該代碼區(qū)域內(nèi)的線程終止或發(fā)生未經(jīng)處理的異常,可能會(huì)危害應(yīng)用程序域中的其他任務(wù)。 |
5 | public static void BeginThreadAffinity() 通知主機(jī)托管代碼將要執(zhí)行依賴于當(dāng)前物理操作系統(tǒng)線程的標(biāo)識(shí)的指令。 |
6 | public static void EndCriticalRegion() 通知主機(jī)將要進(jìn)入一個(gè)代碼區(qū)域,若該代碼區(qū)域內(nèi)的線程終止或發(fā)送未經(jīng)處理的異常,僅會(huì)影響當(dāng)前任務(wù)。 |
7 | public static void EndThreadAffinity() 通知主機(jī)托管代碼已執(zhí)行完依賴于當(dāng)前物理操作系統(tǒng)線程的標(biāo)識(shí)的指令。 |
8 | public static void FreeNamedDataSlot(string name) 消除進(jìn)程中所有線程的名稱與槽之間的關(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)前線程正在其中運(yùn)行的當(dāng)前域。 |
11 | public static AppDomain GetDomainID() 返回唯一的應(yīng)用程序域標(biāo)識(shí)符。 |
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)用線程,直到某個(gè)線程終止為止。此方法有不同的重載形式。 |
15 | public static void MemoryBarrier() 按如下方式同步內(nèi)存存取:執(zhí)行當(dāng)前線程的處理器在對(duì)指令進(jìn)行重新排序時(shí),不能采用先執(zhí)行 MemoryBarrier 調(diào)用之后的內(nèi)存存取,再執(zhí)行 MemoryBarrier 調(diào)用之前的內(nèi)存存取的方式。 |
16 | public static void ResetAbort() 取消當(dāng)前線程請(qǐng)求的 Abort 操作。 |
17 | public static void SetData( LocalDataStoreSlot slot, Object data ) 在指定槽中,設(shè)置當(dāng)前正在運(yùn)行中線程的當(dāng)前域的數(shù)據(jù)。使用以 ThreadStaticAttribute 屬性標(biāo)記的字段,可獲得更好的性能。 |
18 | public void Start() 開(kāi)始一個(gè)線程。 |
19 | public static void Sleep( int millisecondsTimeout ) 令線程暫停一段時(shí)間。 |
20 | public static void SpinWait( int iterations ) 令線程等待一段時(shí)間,時(shí)間長(zhǎng)度由 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 ) 讀取字段的值。無(wú)論處理器的數(shù)目或處理器緩存的狀態(tài)如何,該值都表示由計(jì)算機(jī)中任何一個(gè)處理器寫入的最新值。此方法有不同的重載形式,此處僅給出部分例子。 |
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 ) 立即寫入一個(gè)值到字段中,使該值對(duì)計(jì)算機(jī)中的所有處理器都可見(jiàn)。此方法有不同的重載形式,此處僅給出部分例子。 |
23 | public static bool Yield() 令調(diào)用線程執(zhí)行已準(zhǔn)備好在當(dāng)前處理器上運(yùn)行的另一個(gè)線程,由操作系統(tǒng)選擇要執(zhí)行的線程。 |
線程是通過(guò)擴(kuò)展 Thread 類創(chuàng)建的,擴(kuò)展而來(lái)的 Thread 類調(diào)用 Start() 方法即可開(kāi)始子線程的執(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();
}
}
}
編譯執(zhí)行上述代碼段,得到如下結(jié)果:
In Main: Creating the Child thread
Child thread starts
Thread 類提供了多種用于線程管理的方法。下面的示例調(diào)用了 sleep() 方法來(lái)在一段特定時(shí)間內(nèi)暫停線程:
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();
}
}
}
編譯執(zhí)行上述代碼,得到如下代碼段:
In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
使用 Abort() 方法可銷毀線程。
在運(yùn)行時(shí),通過(guò)拋出 ThreadAbortException 來(lái)終止線程。這個(gè)異常無(wú)法被捕獲,當(dāng)且僅當(dāng)具備 finally 塊時(shí),才將控制送到 finally 塊中。
示例:
using System;
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts");
// 執(zhí)行一些任務(wù),如計(jì)十個(gè)數(shù)
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();
// 將主線程停止一段時(shí)間
Thread.Sleep(2000);
// 中止子線程
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
編譯執(zhí)行上述代碼,得到如下結(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
更多建議: