C#多線程
線程被定義爲程序的執行路徑。每個線程都定義了一個獨特的控制流程。如果應用程序涉及複雜和耗時的操作,那麼設置不同的執行路徑或線程通常有助於每個線程執行特定的作業。
線程是輕量級的進程。使用線程的一個常見示例是通過現代操作系統實現併發編程。使用線程節省了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