瞭解下C# 多執行緒

大雄45發表於2022-07-31
導讀 執行緒被定義為程式的執行路徑。每個執行緒都定義了一個獨特的控制流。如果您的應用程式涉及到複雜的和耗時的操作,那麼設定不同的執行緒執行路徑往往是有益的,每個執行緒執行特定的工作。

執行緒是輕量級程式。一個使用執行緒的常見例項是現代作業系統中並行程式設計的實現。使用執行緒節省了 CPU 週期的浪費,同時提高了應用程式的效率。

到目前為止我們編寫的程式是一個單執行緒作為應用程式的執行例項的單一的過程執行的。但是,這樣子應用程式同時只能執行一個任務。為了同時執行多個任務,它可以被劃分為更小的執行緒。

執行緒生命週期

執行緒生命週期開始於 System.Threading.Thread 類的物件被建立時,結束於執行緒被終止或完成執行時。

下面列出了執行緒生命週期中的各種狀態:

  1. 未啟動狀態:當執行緒例項被建立但 Start 方法未被呼叫時的狀況。
  2. 就緒狀態:當執行緒準備好執行並等待 CPU 週期時的狀況。
  3. 不可執行狀態:下面的幾種情況下執行緒是不可執行的:
  4. 已經呼叫 Sleep 方法
    已經呼叫 Wait 方法
    透過 I/O 操作阻塞

  5. 死亡狀態:當執行緒已完成執行或已中止時的狀況。
主執行緒

在 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 獲取或設定當前執行緒的區域性。
CurrentPrincipal 獲取或設定執行緒的當前負責人(對基於角色的安全性而言)。
CurrentThread 獲取當前正在執行的執行緒。
CurrentUICulture 獲取或設定資源管理器使用的當前區域性以便在執行時查詢區域性特定的資源。
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()
取消為當前執行緒請求的 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
)
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");
            // 執行緒暫停 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();
        }
    }
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
銷燬執行緒

Abort() 方法用於銷燬執行緒。

透過丟擲 threadabortexception 在執行時中止執行緒。這個異常不能被捕獲,如果有 finally 塊,控制會被送至 finally 塊。

下面的程式說明了這點:

例項

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            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");
            }
        }
       
        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();
            // 停止主執行緒一段時間
            Thread.Sleep(2000);
            // 現在中止子執行緒
            Console.WriteLine("In Main: Aborting the Child thread");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

In Main: Creating the Child thread
Child thread starts
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception

原文來自:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2908329/,如需轉載,請註明出處,否則將追究法律責任。

相關文章