線程被定義為程式的執行路徑。每個線程都定義了一個獨特的控制流程。如果應用程式涉及複雜和耗時的操作,那麼設置不同的執行路徑或線程通常有助於每個線程執行特定的作業。
線程是羽量級的進程。使用線程的一個常見示例是通過現代操作系統實現併發編程。使用線程節省了CPU週期並提高了應用程式的效率。
到目前為止,我們編寫了單個線程作為單個進程運行的程式,它是應用程式的運行實例。 但是,這樣應用程式可以一次執行一個作業。為了使它一次執行多個任務,它可以分為較小的線程。
線程生命週期
當創建System.Threading.Thread
類的對象時,線程的生命週期將會啟動,當線程終止或完成執行時,該迴圈將結束。
以下是線程生命週期中的各種狀態:
- 未開始狀態:線程實例創建但不調用
Start
方法的情況。 - 就緒狀態:線程準備運行並等待CPU週期時的情況。
- 不可運行狀態:線程不可執行,有以下幾種情況:
Sleep
方法已被調用Wait
方法已被調用- 被I/O操作阻止
- 死亡狀態:線程完成執行或中止時的情況。
主線程
在 C# 中,System.Threading.Thread
類用於處理線程。它允許在多線程應用程式中創建和訪問單個線程。在進程中執行的第一個線程稱為主線程。
當 C# 程式開始執行時,主線程就會被自動創建。使用Thread
類創建的線程稱為主線程的子線程。可以使用Thread
類的CurrentThread
屬性訪問線程。
以下程式演示主線程執行:
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();
}
}
}
當上述代碼被編譯並執行時,它產生以下結果:
This is MainThread
Thread類的屬性和方法
下表顯示了Thread
類的一些最常用的屬性:
屬性 | 描述 |
---|---|
CurrentContext | 獲取當前正在執行的線程的上下文。 |
CurrentCulture | 獲取或設置當前線程的文化(culture)。 |
CurrentPrinciple | 獲取或設置線程的當前主體(用於基於角色的安全性)。 |
CurrentThread | 獲取當前正在運行的線程。 |
CurrentUICulture | 獲取或設置資源管理器使用的當前文化(culture),以便在運行時查找特定於文化的資源。 |
ExecutionContext | 獲取一個ExecutionContext 對象,該對象包含有關當前線程的各種上下文的資訊。 |
IsAlive | 獲取指示當前線程的執行狀態的值。 |
IsBackground | 獲取或設置一個值,指示線程是否是後臺線程。 |
IsThreadPoolThread | 獲取一個值,指示線程是否屬於託管線程池。 |
ManagedThreadId | 獲取當前受管線程的唯一識別字。 |
Name | 獲取或設置線程的名稱。 |
Priority | 獲取或設置一個指示線程的調度優先順序的值。 |
ThreadState | 獲取包含當前線程的狀態的值。 |
下表顯示了Thread
類最常用的一些方法:
序號 | 方法 | 描述 |
---|---|---|
1 | public void Abort() |
在調用它的線程中引發ThreadAbortException 異常,以開始終止線程的進程。調用此方法通常會終止線程。 |
2 | public static LocalDataStoreSlot AllocateDataSlot() |
在所有線程上分配一個未命名的數據槽。為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性的字段。 |
3 | public static LocalDataStoreSlot AllocateNamedDataSlot(string name) |
在所有線程上分配一個命名的數據槽。為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性的字段。 |
4 | public static void BeginCriticalRegion() |
通知主機執行即將進入的代碼區域,線程中止或未處理的異常的影響可能會危及應用程式域中的其他任務。 |
5 | public static void BeginThreadAffinity() |
通知託管代碼即將執行依賴於當前物理操作系統線程標識的指令。 |
6 | public static void EndCriticalRegion() |
通知主機即將執行即將進入的代碼區域,線程中止或未處理異常的影響限於當前任務。 |
7 | public static void EndThreadAffinity() |
通知託管代碼已完成執行依賴於當前物理操作系統線程標識的指令的主機。 |
8 | public static void FreeNamedDataSlot(string name) |
消除進程中所有線程的名稱和插槽之間的關聯。為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性的字段。 |
9 | public static Object GetData(LocalDataStoreSlot slot) |
從當前線程的當前域中指定插槽中檢索值。為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性的字段。 |
10 | public static AppDomain GetDomain() |
返回當前線程正在運行的當前域。 |
11 | public static AppDomain GetDomainID() |
返回唯一的應用程式域識別字 |
12 | public static LocalDataStoreSlot GetNamedDataSlot(string name) |
查找一個命名的數據槽。為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性的字段。 |
13 | public void Interrupt() |
中斷處於WaitSleepJoin 線程狀態的線程。 |
14 | public void Join() |
阻止調用線程直到線程終止,同時繼續執行標準COM和SendMessage 抽取。此方法具有不同的重載形式。 |
15 | public static void MemoryBarrier() |
同步記憶體訪問如下:執行當前線程的處理器無法重新排序指令,使得在調用MemoryBarrier 之前進行的記憶體訪問在內存訪問之後執行,這些記憶體訪問之後對MemoryBarrier 的調用。 |
16 | public static void ResetAbort() |
取消當前線程中止請求。 |
17 | public static void SetData(LocalDataStoreSlot slot, Object data) |
為當前正在運行的線程的當前域設置指定槽中的數據。為了獲得更好的性能,請改用標記為ThreadStaticAttribute 屬性的字段。 |
18 | public void Start() |
開始一個線程 |
19 | public static void Sleep(int millisecondsTimeout) |
使線程暫停一段時間 |
20 | public static void SpinWait(int iterations) |
使線程等待iterations 參數定義的次數 |
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) |
讀取一個字段的值。該值是電腦中任何處理器寫入的最新值,它不考慮處理器數量或處理器高速緩存的狀態。此方法具有不同的重載形式。上面只給出了幾個。 |
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() |
使調用線程對另一個準備在當前處理器上運行的線程執行執行。操作系統選擇要產生的線程。 |
創建線程
實現線程是通過擴展Thread
類創建的。擴展Thread
類然後調用Start()
方法來開始執行子線程。
以下程式演示了上面所說的概念:
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();
}
}
}
當上述代碼被編譯並執行時,它產生以下結果:
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");
// the thread is paused for 5000 milliseconds
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();
}
}
}
當上述代碼被編譯並執行時,它產生以下結果:
In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
銷毀線程
Abort()
方法用於銷毀線程。運行時通過拋出ThreadAbortException
來中止線程。這個異常不能被捕獲,控件發送到finally
塊(如果有的話)。
以下一個實現線程的程式:
using System;
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts");
// do some work, like counting to 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();
//stop the main thread for some time
Thread.Sleep(2000);
//now abort the child
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
當上述代碼被編譯並執行時,它產生以下結果:
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