ASP.NET - 多執行緒



執行緒定義為程式的執行路徑。每個執行緒定義一個唯一的控制流。如果您的應用程式涉及複雜且耗時的操作,例如資料庫訪問或一些密集的 I/O 操作,那麼設定不同的執行路徑或執行緒通常很有幫助,每個執行緒執行一項特定工作。

執行緒是輕量級程序。執行緒的一個常見示例是現代作業系統實現併發程式設計。使用執行緒可以節省 CPU 週期浪費並提高應用程式效率。

到目前為止,我們編譯的程式中只有一個執行緒作為單個程序執行,該程序是應用程式的執行例項。但是,透過這種方式,應用程式一次只能執行一項工作。為了使其一次執行多個任務,可以將其劃分為較小的執行緒。

在 .Net 中,執行緒透過“System.Threading”名稱空間進行處理。建立System.Threading.Thread型別的變數允許您建立一個新的執行緒開始工作。它允許您建立和訪問程式中的單個執行緒。

建立執行緒

透過建立一個 Thread 物件並向其建構函式提供 ThreadStart 引用來建立執行緒。

ThreadStart childthreat = new ThreadStart(childthreadcall);

執行緒生命週期

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

以下是執行緒生命週期中的各種狀態

  • 未啟動狀態:這是建立執行緒例項但未呼叫 Start 方法的情況。

  • 就緒狀態:這是執行緒已準備好執行並等待 CPU 週期的情況。

  • 不可執行狀態:執行緒不可執行,當

    • 已呼叫 Sleep 方法
    • 已呼叫 Wait 方法
    • 被 I/O 操作阻塞
  • 死亡狀態:這是執行緒已完成執行或已被中止的情況。

執行緒優先順序

Thread 類的 Priority 屬性指定一個執行緒相對於其他執行緒的優先順序。.Net 執行時選擇具有最高優先順序的就緒執行緒。

優先順序可以分為:

  • 高於正常
  • 低於正常
  • 最高
  • 最低
  • 正常

建立執行緒後,使用執行緒類的 Priority 屬性設定其優先順序。

NewThread.Priority = ThreadPriority.Highest;

執行緒屬性和方法

Thread 類具有以下重要屬性

屬性 描述
CurrentContext 獲取執行緒正在執行的當前上下文。
CurrentCulture 獲取或設定當前執行緒的區域性。
CurrentPrinciple 獲取或設定執行緒的當前主體,用於基於角色的安全性。
CurrentThread 獲取當前正在執行的執行緒。
CurrentUICulture 獲取或設定資源管理器在執行時查詢特定於區域性的資源時使用的當前區域性。
ExecutionContext 獲取一個 ExecutionContext 物件,其中包含有關當前執行緒的各種上下文的資訊。
IsAlive 獲取一個值,該值指示當前執行緒的執行狀態。
IsBackground 獲取或設定一個值,該值指示執行緒是否為後臺執行緒。
IsThreadPoolThread 獲取一個值,該值指示執行緒是否屬於託管執行緒池。
ManagedThreadId 獲取當前託管執行緒的唯一識別符號。
Name 獲取或設定執行緒的名稱。
Priority 獲取或設定一個值,該值指示執行緒的排程優先順序。
ThreadState 獲取一個包含當前執行緒狀態的值。

Thread 類具有以下重要方法

方法 描述
Abort 在呼叫它的執行緒中引發 ThreadAbortException,以開始終止執行緒的過程。呼叫此方法通常會終止執行緒。
AllocateDataSlot 在所有執行緒上分配一個未命名的記憶體槽。為了獲得更好的效能,請改用用 ThreadStaticAttribute 屬性標記的欄位。
AllocateNamedDataSlot 在所有執行緒上分配一個命名的記憶體槽。為了獲得更好的效能,請改用用 ThreadStaticAttribute 屬性標記的欄位。
BeginCriticalRegion 通知主機執行即將進入程式碼區域,在該區域中,執行緒中止或未處理異常的影響可能會危及應用程式域中的其他任務。
BeginThreadAffinity 通知主機託管程式碼即將執行依賴於當前物理作業系統執行緒標識的指令。
EndCriticalRegion 通知主機執行即將進入程式碼區域,在該區域中,執行緒中止或未處理異常的影響僅限於當前任務。
EndThreadAffinity 通知主機託管程式碼已完成執行依賴於當前物理作業系統執行緒標識的指令。
FreeNamedDataSlot 消除程序中所有執行緒的名稱和槽之間的關聯。為了獲得更好的效能,請改用用 ThreadStaticAttribute 屬性標記的欄位。
GetData 從當前執行緒的當前域中指定槽中檢索值。為了獲得更好的效能,請改用用 ThreadStaticAttribute 屬性標記的欄位。
GetDomain 返回當前執行緒正在執行的當前域。
GetDomainID 返回唯一的應用程式域識別符號。
GetNamedDataSlot 查詢命名的記憶體槽。為了獲得更好的效能,請改用用 ThreadStaticAttribute 屬性標記的欄位。
Interrupt 中斷處於 WaitSleepJoin 執行緒狀態的執行緒。
Join 阻塞呼叫執行緒,直到執行緒終止,同時繼續執行標準 COM 和 SendMessage 泵送。此方法具有不同的過載形式。
MemoryBarrier 同步記憶體訪問,如下所示:執行當前執行緒的處理器不能重新排序指令,以至於在對 MemoryBarrier 的呼叫之前執行的記憶體訪問在對 MemoryBarrier 的呼叫之後執行的記憶體訪問之後執行。
ResetAbort 取消對當前執行緒請求的 Abort。
SetData 為當前執行執行緒的當前域設定指定槽中的資料。為了獲得更好的效能,請改用用 ThreadStaticAttribute 屬性標記的欄位。
Start 啟動執行緒。
Sleep 使執行緒暫停一段時間。
SpinWait 導致執行緒等待迭代引數定義的次數。
VolatileRead() 讀取欄位的值。該值是計算機中任何處理器寫入的最新值,無論處理器數量或處理器快取狀態如何。此方法具有不同的過載形式。
VolatileWrite() 立即將值寫入欄位,以便該值對計算機中的所有處理器可見。此方法具有不同的過載形式。
Yield 導致呼叫執行緒將執行權讓給另一個已準備好執行在當前處理器上的執行緒。作業系統選擇要讓出的執行緒。

示例

以下示例說明了 Thread 類的用法。頁面有一個標籤控制元件,用於顯示來自子執行緒的訊息。主程式的訊息直接使用 Response.Write() 方法顯示。因此它們出現在頁面的頂部。

原始檔如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="threaddemo._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

   <head runat="server">
      <title>
         Untitled Page
      </title>
   </head>
   
   <body>
      <form id="form1" runat="server">
         <div>
            <h3>Thread Example</h3>
         </div>
         
         <asp:Label ID="lblmessage" runat="server" Text="Label">
         </asp:Label>
      </form>
   </body>
   
</html>

程式碼隱藏檔案如下:

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;

using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;
using System.Threading;

namespace threaddemo
{
   public partial class _Default : System.Web.UI.Page
   {
      protected void Page_Load(object sender, EventArgs e)
      {
         ThreadStart childthreat = new ThreadStart(childthreadcall);
         Response.Write("Child Thread Started <br/>");
         Thread child = new Thread(childthreat);
         
         child.Start();
         
         Response.Write("Main sleeping  for 2 seconds.......<br/>");
         Thread.Sleep(2000);
         Response.Write("<br/>Main aborting child thread<br/>");
         
         child.Abort();
      }
      
      public void childthreadcall()
      {
         try{
            lblmessage.Text = "<br />Child thread started <br/>";
            lblmessage.Text += "Child Thread: Coiunting to 10";
            
            for( int i =0; i<10; i++)
            {
               Thread.Sleep(500);
               lblmessage.Text += "<br/> in Child thread </br>";
            }
            
            lblmessage.Text += "<br/> child thread finished";
            
         }catch(ThreadAbortException e){
         
            lblmessage.Text += "<br /> child thread - exception";
            
         }finally{
            lblmessage.Text += "<br /> child thread - unable to catch the  exception";
         }
      }
   }
}

觀察以下幾點:

  • 載入頁面時,將使用 childthreadcall() 方法的引用啟動一個新執行緒。主執行緒活動直接顯示在網頁上。

  • 第二個執行緒執行並將訊息傳送到標籤控制元件。

  • 主執行緒休眠 2000 毫秒,在此期間子執行緒執行。

  • 子執行緒執行直到被主執行緒中止。它引發 ThreadAbortException 並終止。

  • 控制權返回到主執行緒。

執行程式時,會發送以下訊息:

ASP.NET Thread
廣告