鍍金池/ 教程/ C#/ 多線(xiàn)程
循環(huán)
正則表達(dá)式
概述
委托
多態(tài)性
字符串
繼承
結(jié)構(gòu)體
集合
變量
不安全代碼
判斷
反射
異常處理
可空類(lèi)型
類(lèi)
方法
數(shù)據(jù)類(lèi)型
命名空間
文件 I/O
類(lèi)型轉(zhuǎn)換
屬性
程序結(jié)構(gòu)
事件
接口
預(yù)處理指令
運(yùn)算符
多線(xiàn)程
匿名方法
索引器
泛型
封裝
常量和文字
基本語(yǔ)法
特性
數(shù)組
環(huán)境配置
運(yùn)算符重載
枚舉

多線(xiàn)程

線(xiàn)程的定義是程序的執(zhí)行路徑。每個(gè)線(xiàn)程都定義了一個(gè)獨(dú)特的控制流,如果應(yīng)用程序涉及到復(fù)雜且耗時(shí)的操作,那么設(shè)置不同的線(xiàn)程執(zhí)行路徑會(huì)非常有好處,因?yàn)槊總€(gè)線(xiàn)程會(huì)被指定于執(zhí)行特定的工作。

線(xiàn)程實(shí)際上是輕量級(jí)進(jìn)程。一個(gè)常見(jiàn)的使用線(xiàn)程的實(shí)例是現(xiàn)代操作系統(tǒng)中的并行編程。使用線(xiàn)程不僅有效地減少了 CPU 周期的浪費(fèi),同時(shí)還提高了應(yīng)用程序的運(yùn)行效率。

到目前為止我們所編寫(xiě)的程序都是以一個(gè)單線(xiàn)程作為應(yīng)用程序的運(yùn)行的,其運(yùn)行過(guò)程均為單一的。但是,在這種情況下,應(yīng)用程序在同一時(shí)間只能執(zhí)行一個(gè)任務(wù)。為了使應(yīng)用程序可以同時(shí)執(zhí)行多個(gè)任務(wù),需要將其被劃分為多個(gè)更小的線(xiàn)程。

線(xiàn)程的聲明周期

線(xiàn)程的生命周期開(kāi)始于對(duì)象的 System.Threading.Thread 類(lèi)創(chuàng)建時(shí),結(jié)束于線(xiàn)程被終止或是完成執(zhí)行時(shí)。 下列各項(xiàng)為線(xiàn)程在生命周期中的各種狀態(tài):

  • 未啟動(dòng)狀態(tài):線(xiàn)程實(shí)例已被創(chuàng)建但 Start 方法仍未被調(diào)用時(shí)的狀態(tài)。
  • 就緒狀態(tài):線(xiàn)程已準(zhǔn)備好運(yùn)行,正在等待 CPU 周期時(shí)的狀態(tài)。
  • 不可運(yùn)行狀態(tài):下面的幾種情況下線(xiàn)程是不可運(yùn)行的:
    • 已經(jīng)調(diào)用 Sleep 方法
    • 已經(jīng)調(diào)用 Wait 方法
    • 通過(guò) I/O 操作阻塞
  • 死亡狀態(tài):線(xiàn)程已完成執(zhí)行或已終止的狀態(tài)。

主線(xiàn)程

在 C# 中,System.Threading.Thread 類(lèi)用于線(xiàn)程的工作。它允許創(chuàng)建并訪(fǎng)問(wèn)多線(xiàn)程應(yīng)用程序中的單個(gè)線(xiàn)程。進(jìn)程中第一個(gè)被執(zhí)行的線(xiàn)程稱(chēng)為主線(xiàn)程。

當(dāng) C# 程序開(kāi)始執(zhí)行時(shí),會(huì)自動(dòng)創(chuàng)建主線(xiàn)程。使用 Thread 類(lèi)創(chuàng)建的線(xiàn)程被主線(xiàn)程的子線(xiàn)程調(diào)用。通過(guò) Thread 類(lèi)的 CurrentThread 屬性可以訪(fǎng)問(wèn)線(xiàn)程。

下面的程序演示了主線(xià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 類(lèi)的屬性和方法

下表為 Thread 類(lèi)一些常用的屬性:

屬性 描述
CurrentContext 獲取線(xiàn)程當(dāng)前正在執(zhí)行的線(xiàn)程的上下文。
CurrentCulture 獲取或設(shè)置當(dāng)前線(xiàn)程的區(qū)域性
CurrentPrinciple 獲取或設(shè)置線(xiàn)程的當(dāng)前責(zé)任人(針對(duì)基于角色的安全性)
CurrentThread 獲取當(dāng)前正在運(yùn)行的線(xiàn)程
CurrentUICulture 獲取或設(shè)置資源管理器當(dāng)前所使用的區(qū)域性,便于在運(yùn)行時(shí)查找區(qū)域性特定的資源
ExecutionContext 獲取一個(gè) ExcutionContext 對(duì)象,該對(duì)象包含有關(guān)當(dāng)前線(xiàn)程的各種上下文信息。
IsAlive 獲取一個(gè)值,指示當(dāng)前線(xiàn)程的執(zhí)行狀態(tài)。
IsBackground 獲取或設(shè)置一個(gè)值,指示線(xiàn)程是否為后臺(tái)線(xiàn)程。
IsThreadPoolThread 獲取或設(shè)置一個(gè)值,指示線(xiàn)程是否屬于托管線(xiàn)程池。
ManagedThreadId 獲取當(dāng)前托管線(xiàn)程的唯一標(biāo)識(shí)符
Name 獲取或設(shè)置線(xiàn)程的名稱(chēng)。
Priority 獲取或設(shè)置一個(gè)值,指示線(xiàn)程的調(diào)度優(yōu)先級(jí)
ThreadState 獲取一個(gè)值,指示當(dāng)前線(xiàn)程的狀態(tài)。

下表為 Thread 類(lèi)一些常用的方法:

序號(hào) 方法名和描述
1 public void Abort()
在調(diào)用此方法的線(xiàn)程上引發(fā) ThreadAbortException,則觸發(fā)終止此線(xiàn)程的操作。調(diào)用此方法通常會(huì)終止線(xiàn)程。
2 public static LocalDataStoreSlot AllocateDataSlot()
在所有的線(xiàn)程上分配未命名的數(shù)據(jù)槽。使用以 ThreadStaticAttribute 屬性標(biāo)記的字段,可獲得更好的性能。
3 public static LocalDataStoreSlot AllocateNamedDataSlot( string name)
在所有線(xiàn)程上分配已命名的數(shù)據(jù)槽。使用以 ThreadStaticAttribute 屬性標(biāo)記的字段,可獲得更好的性能。
4 public static void BeginCriticalRegion()
通知主機(jī)將要進(jìn)入一個(gè)代碼區(qū)域,若該代碼區(qū)域內(nèi)的線(xiàn)程終止或發(fā)生未經(jīng)處理的異常,可能會(huì)危害應(yīng)用程序域中的其他任務(wù)。
5 public static void BeginThreadAffinity()
通知主機(jī)托管代碼將要執(zhí)行依賴(lài)于當(dāng)前物理操作系統(tǒng)線(xiàn)程的標(biāo)識(shí)的指令。
6 public static void EndCriticalRegion()
通知主機(jī)將要進(jìn)入一個(gè)代碼區(qū)域,若該代碼區(qū)域內(nèi)的線(xiàn)程終止或發(fā)送未經(jīng)處理的異常,僅會(huì)影響當(dāng)前任務(wù)。
7 public static void EndThreadAffinity()
通知主機(jī)托管代碼已執(zhí)行完依賴(lài)于當(dāng)前物理操作系統(tǒng)線(xiàn)程的標(biāo)識(shí)的指令。
8 public static void FreeNamedDataSlot(string name)
消除進(jìn)程中所有線(xiàn)程的名稱(chēng)與槽之間的關(guān)聯(lián)。使用以 ThreadStaticAttribute 屬性標(biāo)記的字段,可獲得更好的性能。
9 public static Object GetData( LocalDataStoreSlot slot )
在當(dāng)前線(xiàn)程的當(dāng)前域中從當(dāng)前線(xiàn)程上指定的槽中檢索值。使用以 ThreadStaticAttribute 屬性標(biāo)記的字段,可獲得更好的性能。
10 public static AppDomain GetDomain()
返回當(dāng)前線(xiàn)程正在其中運(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 線(xiàn)程狀態(tài)的線(xiàn)程。
14 public void Join()
在繼續(xù)執(zhí)行標(biāo)準(zhǔn)的 COM 和 SendMessage 消息泵處理期間,阻塞調(diào)用線(xiàn)程,直到某個(gè)線(xiàn)程終止為止。此方法有不同的重載形式。
15 public static void MemoryBarrier()
按如下方式同步內(nèi)存存取:執(zhí)行當(dāng)前線(xiàn)程的處理器在對(duì)指令進(jìn)行重新排序時(shí),不能采用先執(zhí)行 MemoryBarrier 調(diào)用之后的內(nèi)存存取,再執(zhí)行 MemoryBarrier 調(diào)用之前的內(nèi)存存取的方式。
16 public static void ResetAbort()
取消當(dāng)前線(xiàn)程請(qǐng)求的 Abort 操作。
17 public static void SetData( LocalDataStoreSlot slot, Object data )
在指定槽中,設(shè)置當(dāng)前正在運(yùn)行中線(xiàn)程的當(dāng)前域的數(shù)據(jù)。使用以 ThreadStaticAttribute 屬性標(biāo)記的字段,可獲得更好的性能。
18 public void Start()
開(kāi)始一個(gè)線(xiàn)程。
19 public static void Sleep( int millisecondsTimeout )
令線(xiàn)程暫停一段時(shí)間。
20 public static void SpinWait( int iterations )
令線(xiàn)程等待一段時(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è)處理器寫(xiě)入的最新值。此方法有不同的重載形式,此處僅給出部分例子。
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 )
立即寫(xiě)入一個(gè)值到字段中,使該值對(duì)計(jì)算機(jī)中的所有處理器都可見(jiàn)。此方法有不同的重載形式,此處僅給出部分例子。
23 public static bool Yield()
令調(diào)用線(xiàn)程執(zhí)行已準(zhǔn)備好在當(dāng)前處理器上運(yùn)行的另一個(gè)線(xiàn)程,由操作系統(tǒng)選擇要執(zhí)行的線(xiàn)程。

線(xiàn)程的創(chuàng)建

線(xiàn)程是通過(guò)擴(kuò)展 Thread 類(lèi)創(chuàng)建的,擴(kuò)展而來(lái)的 Thread 類(lèi)調(diào)用 Start() 方法即可開(kāi)始子線(xiàn)程的執(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

線(xiàn)程的管理

Thread 類(lèi)提供了多種用于線(xiàn)程管理的方法。 下面的示例調(diào)用了 sleep() 方法來(lái)在一段特定時(shí)間內(nèi)暫停線(xiàn)程:

using System;
using System.Threading;

namespace MultithreadingApplication
{
   class ThreadCreationProgram
   {
      public static void CallToChildThread()
      {
         Console.WriteLine("Child thread starts");

         // 令線(xiàn)程暫停 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

線(xiàn)程的銷(xiāo)毀

使用 Abort() 方法可銷(xiāo)毀線(xiàn)程。

在運(yùn)行時(shí),通過(guò)拋出 ThreadAbortException 來(lái)終止線(xiàn)程。這個(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();

         // 將主線(xiàn)程停止一段時(shí)間
         Thread.Sleep(2000);

         // 中止子線(xiàn)程
         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
上一篇:委托