線程被定義為程式的執行路徑。 每個線程定義一個獨特的控制流程。 如果應用程式涉及複雜和耗時的操作(如數據庫訪問或某些緊張的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
類具有以下重要的屬性:
編號 | 屬性 | 描述 |
---|---|---|
1 | CurrentContext |
獲取線程正在執行的當前上下文。 |
2 | CurrentCulture |
獲取或設置當前線程的文化。 |
3 | CurrentPrinciple |
獲取或設置線程當前的基於角色的安全性的主體。 |
4 | CurrentThread |
獲取當前正在運行的線程。 |
5 | CurrentUICulture |
獲取或設置資源管理器在運行時查找文化特定資源的當前文化。 |
6 | ExecutionContext |
獲取一個ExecutionContext 對象,其中包含有關當前線程的各種上下文的資訊。 |
7 | IsAlive |
獲取一個指示當前線程執行狀態的值。 |
8 | IsBackground |
獲取或設置一個值,該值指示線程是否為後臺線程。 |
9 | IsThreadPoolThread |
獲取一個值,該值指示線程是否屬於託管線程池。 |
10 | ManagedThreadId |
獲取當前託管線程的唯一識別字。 |
11 | Name |
獲取或設置線程的名稱。 |
12 | Priority |
獲取或設置一個指示線程調度優先順序的值。 |
13 | ThreadState |
獲取包含當前線程狀態的值。 |
Thread
類具有以下重要的方法:
編號 | 方法 | 描述 |
---|---|---|
1 | Abort |
在調用它的線程中引發ThreadAbortException 異常,以開始終止線程的過程。 調用這個方法通常會終止線程。 |
2 | AllocateDataSlot |
在所有線程上分配一個未命名的數據插槽。為了獲得更好的性能,請使用ThreadStaticAttribute 屬性標記字段。 |
3 | AllocateNamedDataSlot |
在所有線程上分配一個指定的數據插槽。 為了獲得更好的性能,請使用ThreadStaticAttribute 屬性標記字段。 |
4 | BeginCriticalRegion |
通知主機執行即將進入一個線程中止或未處理異常的影響可能危及應用程式域中的其他任務的代碼區域。 |
5 | BeginThreadAffinity |
通知主機託管代碼即將執行取決於當前物理操作系統線程標識的指令。 |
6 | EndCriticalRegion |
通知主機執行即將進入一個線程中止或未處理異常的影響被限制在當前任務的代碼區域。 |
7 | EndThreadAffinity |
通知主機,託管代碼已經完成執行取決於當前物理操作系統線程的標識的指令。 |
8 | FreeNamedDataSlot |
消除進程中所有線程的名稱和插槽之間的關聯。 為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性字段。 |
9 | GetData |
從當前線程的當前域內的當前線程的指定插槽中檢索值。 為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性字段。 |
10 | GetDomain |
返回當前線程正在運行的當前域。 |
11 | GetDomainID |
返回唯一的應用程式域識別字。 |
12 | GetNamedDataSlot |
查找一個命名的數據插槽。 為了獲得更好的性能,請使用ThreadStaticAttribute 屬性標記字段。 |
13 | Interrupt |
中斷處於WaitSleepJoin 線程狀態的線程。 |
14 | Join |
阻塞調用線程,直到線程終止,同時繼續執行標準COM和SendMessage 抽取。這種方法有不同的重載形式。 |
15 | MemoryBarrier |
同步記憶體訪問,如下所示:執行當前線程的處理器不能重新排序指令,以便在調用MemoryBarrier 之前執行記憶體訪問之後,訪問MemoryBarrier 調用之後的記憶體訪問。 |
16 | ResetAbort |
取消當前線程所請求的中止。 |
17 | SetData |
在當前正在運行的線程的指定槽中設置該線程當前域的數據。為了獲得更好的性能,請使用標記為ThreadStaticAttribute 屬性的字段。 |
18 | Start |
開始一個線程。 |
19 | Sleep |
使線程暫停一段時間。 |
20 | SpinWait |
使線程等待迭代參數定義的次數。 |
21 | VolatileRead() |
讀取一個字段的值。該值是電腦中任何處理器寫入的最新值,無論處理器的數量或處理器高速緩存的狀態如何。這種方法有不同的重載形式。 |
22 | VolatileWrite() |
立即將值寫入字段,以便電腦中的所有處理器都可以看到該值。 這種方法有不同的重載形式。 |
23 | Yield |
使調用線程產生執行到另一個準備在當前處理器上運行的線程。 操作系統選擇要產生的線程。 |
示例
以下示例說明了Thread
類的用法。該頁面具有用於顯示來自子線程的消息的標籤控件。 來自主程序的消息直接使用Response.Write()
方法顯示。 因此,它們出現在頁面的頂部。
首先打開Visual Studio,創建一個名稱為:MultiThreading 的ASP.Net空網站 專案。並添加一個Web窗體檔 - Default.aspx
原始檔案(Default.aspx)如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>ASP.Net多線程示例</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h3>ASP.Net多線程示例</h3>
</div>
<asp:Label ID="lblmessage" runat="server" Text="Label">
</asp:Label>
</form>
</body>
</html>
後端代碼檔(Default.aspx.cs)如下:
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;
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
異常並終止。 - 控制權返回到主線程。
運行專案程式後,得到以下結果 -