鍍金池/ 教程/ C#/ C#多線程
C#屬性(Properties)
C#與Java比較
C#方法
C#枚舉
C#關(guān)鍵字
C# StreamReader類
C#不安全代碼
C#文件(I/O)
C#匿名方法
C#線程同步
C# Thread類
C#主線程
C#數(shù)據(jù)類型
C# FileStream類
C#預(yù)處理指令
C#繼承
C#循環(huán)
C#決策結(jié)構(gòu)
C#集合
C#反射
C#類型轉(zhuǎn)換
C#泛型
C# StringReader類
C#歷史
C#運(yùn)算符重載
C#屬性
C#線程實(shí)例:Sleep()方法
C#線程示例:優(yōu)先級(jí)
C#線程實(shí)例:Join()方法
C# BinaryReader類
C#類
C#索引器
C# BinaryWriter類
C#序列化
C#常量和文字
C#程序結(jié)構(gòu)
C#封裝
C#事件
C#可空類型(nullable)
C#基本語法
C#異常處理
C#教程
C#接口
C# System.IO命名空間
C#線程命名實(shí)例
C# StringWriter類
C#線程實(shí)例
C#數(shù)組
C#正則表達(dá)式
C#命名空間
C#反序列化
C#與C++比較
C# TextWriter類
C#多線程
C#字符串
C#是什么?
C#變量
C# FileInfo類
C#線程實(shí)例:Abort()方法
C#結(jié)構(gòu)體
C#運(yùn)算符
C#入門程序
C#多線程生命周期
C# TextReader類
C# DirectoryInfo類
C#委托

C#多線程

線程被定義為程序的執(zhí)行路徑。每個(gè)線程都定義了一個(gè)獨(dú)特的控制流程。如果應(yīng)用程序涉及復(fù)雜和耗時(shí)的操作,那么設(shè)置不同的執(zhí)行路徑或線程通常有助于每個(gè)線程執(zhí)行特定的作業(yè)。

線程是輕量級(jí)的進(jìn)程。使用線程的一個(gè)常見示例是通過現(xiàn)代操作系統(tǒng)實(shí)現(xiàn)并發(fā)編程。使用線程節(jié)省了CPU周期并提高了應(yīng)用程序的效率。

到目前為止,我們編寫了單個(gè)線程作為單個(gè)進(jìn)程運(yùn)行的程序,它是應(yīng)用程序的運(yùn)行實(shí)例。 但是,這樣應(yīng)用程序可以一次執(zhí)行一個(gè)作業(yè)。為了使它一次執(zhí)行多個(gè)任務(wù),它可以分為較小的線程。

線程生命周期

當(dāng)創(chuàng)建System.Threading.Thread類的對(duì)象時(shí),線程的生命周期將會(huì)啟動(dòng),當(dāng)線程終止或完成執(zhí)行時(shí),該循環(huán)將結(jié)束。

以下是線程生命周期中的各種狀態(tài):

  • 未開始狀態(tài):線程實(shí)例創(chuàng)建但不調(diào)用Start方法的情況。
  • 就緒狀態(tài):線程準(zhǔn)備運(yùn)行并等待CPU周期時(shí)的情況。
  • 不可運(yùn)行狀態(tài):線程不可執(zhí)行,有以下幾種情況:
    • Sleep方法已被調(diào)用
    • Wait方法已被調(diào)用
    • I/O操作阻止
  • 死亡狀態(tài):線程完成執(zhí)行或中止時(shí)的情況。

主線程

在 C# 中,System.Threading.Thread類用于處理線程。它允許在多線程應(yīng)用程序中創(chuàng)建和訪問單個(gè)線程。在進(jìn)程中執(zhí)行的第一個(gè)線程稱為主線程。

當(dāng) C# 程序開始執(zhí)行時(shí),主線程就會(huì)被自動(dòng)創(chuàng)建。使用Thread類創(chuàng)建的線程稱為主線程的子線程??梢允褂?code>Thread類的CurrentThread屬性訪問線程。

以下程序演示主線程執(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();
      }
   }
}

當(dāng)上述代碼被編譯并執(zhí)行時(shí),它產(chǎn)生以下結(jié)果:

This is MainThread

Thread類的屬性和方法

下表顯示了Thread類的一些最常用的屬性:

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

下表顯示了Thread類最常用的一些方法:

序號(hào) 方法 描述
1 public void Abort() 在調(diào)用它的線程中引發(fā)ThreadAbortException異常,以開始終止線程的進(jìn)程。調(diào)用此方法通常會(huì)終止線程。
2 public static LocalDataStoreSlot AllocateDataSlot() 在所有線程上分配一個(gè)未命名的數(shù)據(jù)槽。為了獲得更好的性能,請(qǐng)使用標(biāo)記為ThreadStaticAttribute屬性的字段。
3 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) 在所有線程上分配一個(gè)命名的數(shù)據(jù)槽。為了獲得更好的性能,請(qǐng)使用標(biāo)記為ThreadStaticAttribute屬性的字段。
4 public static void BeginCriticalRegion() 通知主機(jī)執(zhí)行即將進(jìn)入的代碼區(qū)域,線程中止或未處理的異常的影響可能會(huì)危及應(yīng)用程序域中的其他任務(wù)。
5 public static void BeginThreadAffinity() 通知托管代碼即將執(zhí)行依賴于當(dāng)前物理操作系統(tǒng)線程標(biāo)識(shí)的指令。
6 public static void EndCriticalRegion() 通知主機(jī)即將執(zhí)行即將進(jìn)入的代碼區(qū)域,線程中止或未處理異常的影響限于當(dāng)前任務(wù)。
7 public static void EndThreadAffinity() 通知托管代碼已完成執(zhí)行依賴于當(dāng)前物理操作系統(tǒng)線程標(biāo)識(shí)的指令的主機(jī)。
8 public static void FreeNamedDataSlot(string name) 消除進(jìn)程中所有線程的名稱和插槽之間的關(guān)聯(lián)。為了獲得更好的性能,請(qǐng)使用標(biāo)記為ThreadStaticAttribute屬性的字段。
9 public static Object GetData(LocalDataStoreSlot slot) 從當(dāng)前線程的當(dāng)前域中指定插槽中檢索值。為了獲得更好的性能,請(qǐng)使用標(biāo)記為ThreadStaticAttribute屬性的字段。
10 public static AppDomain GetDomain() 返回當(dāng)前線程正在運(yùn)行的當(dāng)前域。
11 public static AppDomain GetDomainID() 返回唯一的應(yīng)用程序域標(biāo)識(shí)符
12 public static LocalDataStoreSlot GetNamedDataSlot(string name) 查找一個(gè)命名的數(shù)據(jù)槽。為了獲得更好的性能,請(qǐng)使用標(biāo)記為ThreadStaticAttribute屬性的字段。
13 public void Interrupt() 中斷處于WaitSleepJoin線程狀態(tài)的線程。
14 public void Join() 阻止調(diào)用線程直到線程終止,同時(shí)繼續(xù)執(zhí)行標(biāo)準(zhǔn)COM和SendMessage抽取。此方法具有不同的重載形式。
15 public static void MemoryBarrier() 同步存儲(chǔ)器訪問如下:執(zhí)行當(dāng)前線程的處理器無法重新排序指令,使得在調(diào)用MemoryBarrier之前進(jìn)行的存儲(chǔ)器訪問在內(nèi)存訪問之后執(zhí)行,這些內(nèi)存訪問之后對(duì)MemoryBarrier的調(diào)用。
16 public static void ResetAbort() 取消當(dāng)前線程中止請(qǐng)求。
17 public static void SetData(LocalDataStoreSlot slot, Object data) 為當(dāng)前正在運(yùn)行的線程的當(dāng)前域設(shè)置指定槽中的數(shù)據(jù)。為了獲得更好的性能,請(qǐng)改用標(biāo)記為ThreadStaticAttribute屬性的字段。
18 public void Start() 開始一個(gè)線程
19 public static void Sleep(int millisecondsTimeout) 使線程暫停一段時(shí)間
20 public static void SpinWait(int iterations) 使線程等待iterations參數(shù)定義的次數(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) 讀取一個(gè)字段的值。該值是計(jì)算機(jī)中任何處理器寫入的最新值,它不考慮處理器數(shù)量或處理器高速緩存的狀態(tài)。此方法具有不同的重載形式。上面只給出了幾個(gè)。
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) 立即將值寫入字段,以便該值對(duì)計(jì)算機(jī)中的所有處理器可見。此方法具有不同的重載形式。上面只給出了幾個(gè)。
23 public static bool Yield() 使調(diào)用線程對(duì)另一個(gè)準(zhǔn)備在當(dāng)前處理器上運(yùn)行的線程執(zhí)行執(zhí)行。操作系統(tǒng)選擇要產(chǎn)生的線程。

創(chuàng)建線程

實(shí)現(xiàn)線程是通過擴(kuò)展Thread類創(chuàng)建的。擴(kuò)展Thread類然后調(diào)用Start()方法來開始執(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();
      }
   }
}

當(dāng)上述代碼被編譯并執(zhí)行時(shí),它產(chǎn)生以下結(jié)果:

In Main: Creating the Child thread
Child thread starts

管理線程

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

以下示例演示了如何使用sleep()方法在特定時(shí)間段內(nèi)暫停線程。

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();
      }
   }
}

當(dāng)上述代碼被編譯并執(zhí)行時(shí),它產(chǎn)生以下結(jié)果:

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

銷毀線程

Abort()方法用于銷毀線程。運(yùn)行時(shí)通過拋出ThreadAbortException來中止線程。這個(gè)異常不能被捕獲,控件發(fā)送到finally塊(如果有的話)。

以下一個(gè)實(shí)現(xiàn)線程的程序:

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();
      }
   }
}

當(dāng)上述代碼被編譯并執(zhí)行時(shí),它產(chǎn)生以下結(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