ASP.NET 多线程
线程被定义为程序的执行路径。每个线程定义一个独特的控制流。如果您的应用程序涉及复杂且耗时的操作,例如数据库访问或一些密集的 I/O 操作,那么设置不同的执行路径或线程通常会很有帮助,每个线程执行特定的工作。
线程是轻量级进程。使用线程的一个常见示例是现代操作系统实现并发编程。线程的使用节省了CPU周期的浪费,提高了应用程序的效率。
到目前为止,我们编译的程序中,单个线程作为单个进程运行,该进程是应用程序的运行实例。但是,通过这种方式,应用程序可以一次执行一项工作。为了使其一次执行多个任务,可以将其划分为更小的线程。
在 .Net 中,线程是通过"System.Threading"命名空间处理的。创建
System.Threading.Thread 类型的变量允许您创建一个新线程以开始使用。它允许您在程序中创建和访问单个线程。
创建线程
一个线程是通过创建一个 Thread 对象来创建的,给它的构造函数一个 ThreadStart 引用。
ThreadStart childthreat = new ThreadStart(childthreadcall);
线程生命周期
线程的生命周期在 System.Threading.Thread 类的对象被创建时开始,在线程终止或完成执行时结束。
以下是线程生命周期中的各种状态:
Unstarted State : 就是线程的实例已经创建但没有调用Start方法的情况。
Ready State : 这是线程准备好执行并等待 CPU 周期的情况。
不可运行状态:线程不可运行,当:
睡眠方法已被调用
等待方法已被调用
被 I/O 操作阻止
The Dead State : 这是线程完成执行或被中止的情况。
线程优先级
Thread 类的 Priority 属性指定一个线程相对于另一个线程的优先级。 .Net 运行时选择具有最高优先级的就绪线程。
优先级可以分类为:
Above normal
Below normal
Highest
Lowest
Normal
创建线程后,将使用线程类的 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 |
取消为当前线程请求的中止。 |
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 并被终止。
控制权返回到主线程。
程序在执行时发送以下消息:
