天天看點

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 類常用的屬性和方法

下表列出了

類的一些常用的

屬性

描述
CurrentContext 擷取線程正在其中執行的目前上下文。
CurrentCulture 擷取或設定目前線程的區域性。
CurrentPrincipal 擷取或設定線程的目前負責人(對基于角色的安全性而言)。
擷取目前正在運作的線程。
CurrentUICulture 擷取或設定資料總管使用的目前區域性以便在運作時查找區域性特定的資源。
ExecutionContext 擷取一個 ExecutionContext 對象,該對象包含有關目前線程的各種上下文的資訊。
IsAlive 擷取一個值,該值訓示目前線程的執行狀态。
IsBackground 擷取或設定一個值,該值訓示某個線程是否為背景線程。
IsThreadPoolThread 擷取一個值,該值訓示線程是否屬于托管線程池。
ManagedThreadId 擷取目前托管線程的唯一辨別符。
Name 擷取或設定線程的名稱。
Priority 擷取或設定一個值,該值訓示線程的排程優先級。
ThreadState 擷取一個值,該值包含目前線程的狀态。
方法
序号 方法名 & 描述
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() 取消為目前線程請求的 Abort。
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

ref double address,

double value

ref int address,

int value

ref Object address,

Object value

立即向字段寫入一個值,以使該值對計算機中的所有處理器都可見。此方法有不同的重載形式。這裡隻給出了一些形式。
23 public static bool Yield() 導緻調用線程執行準備好在目前處理器上運作的另一個線程。由作業系統選擇要執行的線程。

建立線程

線程是通過擴充 Thread 類建立的。擴充的 Thread 類調用

Start()

方法來開始子線程的執行。

下面的程式示範了這個概念:

    class ThreadCreationProgram

        public static void CallToChildThread()

            Console.WriteLine("Child thread starts");

            ThreadStart childref = new ThreadStart(CallToChildThread);

            Console.WriteLine("In Main: Creating the Child thread");

            Thread childThread = new Thread(childref);

            childThread.Start();

In Main: Creating the Child thread
Child thread starts
      

管理線程

Thread 類提供了各種管理線程的方法。

下面的執行個體示範了

sleep()

方法的使用,用于在一個特定的時間暫停線程。

            // 線程暫停 5000 毫秒

            int sleepfor = 5000;

            Console.WriteLine("Child Thread Paused for {0} seconds",

                              sleepfor / 1000);

            Thread.Sleep(sleepfor);

            Console.WriteLine("Child thread resumes");

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
      

銷毀線程

Abort()

方法用于銷毀線程。

通過抛出

threadabortexception

在運作時中止線程。這個異常不能被捕獲,如果有 finally 塊,控制會被送至 finally 塊。

下面的程式說明了這點:

            try

            {

                Console.WriteLine("Child thread starts");

                // 計數到 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");

            // 停止主線程一段時間

            Thread.Sleep(2000);

            // 現在中止子線程

            Console.WriteLine("In Main: Aborting the Child thread");

            childThread.Abort();

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