top
Loading...
C# 多線程

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獲取或設置當前線程的區域性。
CurrentPrinciple獲取或設置線程的當前負責人(對基於角色的安全性而言)。
CurrentThread獲取當前正在運行的線程。
CurrentUICulture獲取或設置資源管理器使用的當前區域性以便在運行時查找區域性特定的資源。
ExecutionContext獲取一個 ExecutionContext 對象,該對象包含有關當前線程的各種上下文的信息。
IsAlive獲取一個值,該值指示當前線程的執行狀態。
IsBackground獲取或設置一個值,該值指示某個線程是否為後台線程。
IsThreadPoolThread獲取一個值,該值指示線程是否屬於託管線程池。
ManagedThreadId獲取當前託管線程的唯一標識符。
Name獲取或設置線程的名稱。
Priority獲取或設置一個值,該值指示線程的調度優先級。
ThreadState獲取一個值,該值包含當前線程的狀態。

下表列出了 Thread 類的一些常用的 方法

序號方法名 & 描述
1public void Abort()
在調用此方法的線程上引發 ThreadAbortException,以開始終止此線程的過程。調用此方法通常會終止線程。
2public static LocalDataStoreSlot AllocateDataSlot()
在所有的線程上分配未命名的數據槽。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標記的字段。
3public static LocalDataStoreSlot AllocateNamedDataSlot( string name)
在所有線程上分配已命名的數據槽。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標記的字段。
4public static void BeginCriticalRegion()
通知主機執行將要進入一個代碼區域,在該代碼區域內線程中止或未經處理的異常的影響可能會危害應用程序域中的其他任務。
5public static void BeginThreadAffinity()
通知主機託管代碼將要執行依賴於當前物理操作系統線程的標識的指令。
6public static void EndCriticalRegion()
通知主機執行將要進入一個代碼區域,在該代碼區域內線程中止或未經處理的異常僅影響當前任務。
7public static void EndThreadAffinity()
通知主機託管代碼已執行完依賴於當前物理操作系統線程的標識的指令。
8public static void FreeNamedDataSlot(string name)
為進程中的所有線程消除名稱與槽之間的關聯。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標記的字段。
9public static Object GetData( LocalDataStoreSlot slot )
在當前線程的當前域中從當前線程上指定的槽中檢索值。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標記的字段。
10public static AppDomain GetDomain()
返回當前線程正在其中運行的當前域。
11public static AppDomain GetDomainID()
返回唯一的應用程序域標識符。
12public static LocalDataStoreSlot GetNamedDataSlot( string name )
查找已命名的數據槽。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標記的字段。
13public void Interrupt()
中斷處於 WaitSleepJoin 線程狀態的線程。
14public void Join()
在繼續執行標准的 COM 和 SendMessage 消息泵處理期間,阻塞調用線程,直到某個線程終止為止。此方法有不同的重載形式。
15public static void MemoryBarrier()
按如下方式同步內存存取:執行當前線程的處理器在對指令重新排序時,不能采用先執行 MemoryBarrier 調用之後的內存存取,再執行 MemoryBarrier 調用之前的內存存取的方式。
16public static void ResetAbort()
取消為當前線程請求的 Abort。
17public static void SetData( LocalDataStoreSlot slot, Object data )
在當前正在運行的線程上為此線程的當前域在指定槽中設置數據。為了獲得更好的性能,請改用以 ThreadStaticAttribute 屬性標記的字段。
18public void Start()
開始一個線程。
19public static void Sleep( int millisecondsTimeout )
讓線程暫停一段時間。
20public static void SpinWait( int iterations )
導致線程等待由 iterations 參數定義的時間量。
21public 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 )

讀取字段值。無論處理器的數目或處理器緩存的狀態如何,該值都是由計算機的任何處理器寫入的最新值。此方法有不同的重載形式。這里只給出了一些形式。
22public 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 )

立即向字段寫入一個值,以使該值對計算機中的所有處理器都可見。此方法有不同的重載形式。這里只給出了一些形式。
23public 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
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception 
北斗有巢氏 有巢氏北斗