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