ASP.NET 多线程
线程被定义为程序的执行路径。每个线程定义一个独特的控制流。如果你的应用程序涉及复杂且耗时的操作,例如数据库访问或一些密集的 I/O 操作,那么设置不同的执行路径或线程通常很有帮助,每个线程执行特定的作业。
线程是轻量级进程。使用线程的一个常见示例是现代操作系统实现并发编程。使用线程可以节省 CPU 周期的浪费并提高应用程序的效率。
到目前为止,我们编译了单个线程作为单个进程运行的程序,该进程是应用程序的运行实例。但是,这样应用程序一次可以执行一项工作。为了使其一次执行多个任务,可以将其划分为较小的线程。
在 .Net 中,线程是通过“System.Threading”命名空间处理的。创建一个变量 System.Threading.Thread type 允许你创建一个新线程以开始使用。它允许你在程序中创建和访问各个线程。
创建线程
通过创建 Thread 对象来创建线程,并为其构造函数提供 ThreadStart 引用。
ThreadStart childthreat = new ThreadStart(childthreadcall);
线程生命周期
线程的生命周期从创建 System.Threading.Thread 类的对象开始,到线程终止或完成执行结束。
以下是线程生命周期中的各种状态:
-
未开始的状态 : 就是创建了线程的实例但是没有调用Start方法的情况。
-
就绪状态 :是线程准备好执行并等待CPU周期的情况。
-
不可运行状态 :线程不可运行,当:
- 睡眠方法已被调用
- 已调用等待方法
- 被 I/O 操作阻塞
-
死状态 : 是线程已完成执行或已中止的情况。
线程优先级
Thread 类的 Priority 属性指定一个线程相对于另一个线程的优先级。 .Net 运行时选择具有最高优先级的就绪线程。
优先级可分为:
- 超出正常水平
- 低于一般
- Highest
- Lowest
- Normal
创建线程后,使用线程类的 Priority 属性设置其优先级。
NewThread.Priority = ThreadPriority.Highest;
线程属性和方法
Thread 类具有以下重要属性:
Property | 描述 |
---|---|
当前上下文 | 获取线程正在执行的当前上下文。 |
当前文化 | 获取或设置当前线程的区域性。 |
当前原则 | 获取或设置线程的当前主体以实现基于角色的安全性。 |
当前线程 | 获取当前正在运行的线程。 |
当前UICulture | 获取或设置资源管理器用于在运行时查找特定于区域性的资源的当前区域性。 |
执行上下文 | 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。 |
IsAlive | 获取一个值,该值指示当前线程的执行状态。 |
是背景 | 获取或设置一个值,该值指示线程是否为后台线程。 |
IsThreadPoolThread | 获取一个值,该值指示线程是否属于托管线程池。 |
ManagedThreadId | 获取当前托管线程的唯一标识符。 |
Name | 获取或设置线程的名称。 |
Priority | 获取或设置一个值,该值指示线程的调度优先级。 |
线程状态 | 获取一个包含当前线程状态的值。 |
Thread 类具有以下重要方法:
Methods | 描述 |
---|---|
Abort | 在调用它的线程中引发 ThreadAbortException,以开始终止线程的过程。调用此方法通常会终止线程。 |
分配数据槽 | 在所有线程上分配一个未命名的数据槽。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。 |
分配命名数据槽 | 在所有线程上分配一个命名数据槽。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。 |
开始临界区 | 通知主机执行即将进入代码区域,其中线程中止或未处理异常的影响可能危及应用程序域中的其他任务。 |
开始线程关联 | 通知主机托管代码即将执行取决于当前物理操作系统线程标识的指令。 |
EndCriticalRegion | 通知主机执行即将进入代码区域,其中线程中止或未处理异常的影响仅限于当前任务。 |
EndThreadAffinity | 通知主机托管代码已完成执行依赖于当前物理操作系统线程标识的指令。 |
自由命名数据槽 | 消除进程中所有线程的名称和插槽之间的关联。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。 |
GetData | 从当前线程的当前域内的当前线程上的指定槽中检索值。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。 |
获取域 | 返回当前线程正在运行的当前域。 |
获取域ID | 返回唯一的应用程序域标识符。 |
GetNamedDataSlot | 查找命名数据槽。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。 |
打断 | 中断处于 WaitSleepJoin 线程状态的线程。 |
Join | 阻塞调用线程直到线程终止,同时继续执行标准 COM 和 SendMessage 泵送。此方法具有不同的重载形式。 |
记忆屏障 | 同步内存访问如下:执行当前线程的处理器不能以这样的方式重新排序指令,即调用 MemoryBarrier 之前的内存访问在调用 MemoryBarrier 之后的内存访问之后执行。 |
重置中止 | 取消为当前线程请求的 Abort。 |
SetData | 为该线程的当前域设置当前运行线程上指定槽中的数据。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。 |
Start | 启动一个线程。 |
Sleep | 使线程暂停一段时间。 |
SpinWait | 使线程等待由迭代参数定义的次数。 |
挥发性读() | 读取字段的值。无论处理器的数量或处理器缓存的状态如何,该值都是计算机中任何处理器写入的最新值。此方法具有不同的重载形式。 |
挥发性写入() | 立即将值写入字段,以便计算机中的所有处理器都可以看到该值。此方法具有不同的重载形式。 |
Yield | 使调用线程让步给准备好在当前处理器上运行的另一个线程。操作系统选择要屈服的线程。 |
例子
以下示例说明了 Thread 类的用法。该页面有一个标签控件,用于显示来自子线程的消息。来自主程序的消息使用 Response.Write() 方法直接显示。因此它们出现在页面顶部。
源文件如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="threaddemo._Default" %> <!DOCTYPE html PUBLIC "-// W3C <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 例子</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 并被终止。
-
控制返回到主线程。
执行时,程序会发送以下消息: