在.NET中的线程处理(6)

原创 2002年04月22日 09:38:00

使用线程和线程处理<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

创建、管理和销毁托管线程是非常容易的,但如果不了解托管线程和非托管线程之间的关系以及 ThreadAbortException,则这样做可能会导致预料不到的副作用。

创建线程  [C#]

在创建操作系统进程时,操作系统将插入一个线程以执行该进程(包括任何原始应用程序域)中的代码。从此刻起,就可以创建和销毁应用程序域,而不必创建或销毁任何操作系统线程。如果正在执行的代码是托管代码,则可以通过在线程类 Thread.CurrentThread 上检索静态属性来获取正在当前应用程序域中执行的线程的 Thread 对象。

创建 Thread 对象的新实例时,将创建新的托管线程。Thread 的构造函数采用 ThreadStart 委托作为其唯一参数,该委托用于包装在调用 Thread.Start 时由新的 Thread 调用的方法。多次调用 Thread.Start 将引发 ThreadStateException。

Thread.Start 向系统提交异步请求,并且该调用可能在新的线程实际启动之前立即返回。可以使用 Thread.ThreadState 和 Thread.IsAlive 在任一时刻确定线程的状态。Thread.Abort 中止线程,并对其进行标记以进行垃圾回收。下面的代码示例创建两个新线程以调用另一个对象上的实例和静态方法。

重要的一点是,线程还能够调用带参数的方法,即使 ThreadStart 委托只带一个参数——表示状态的对象。正是该对象应将参数传送给被调用方法。下面的简单代码示例说明了一种使用状态对象来传递参数的方法。

暂停和继续线程

在启动线程后,通常想将该线程暂停一段固定时间。调用 Thread.Sleep 将使当前线程立即阻塞一段时间(该时间是传递给 Sleep 的毫秒数),并将其时间片的剩余部分提供给另一个线程。一个线程不能对另一个线程调用 Sleep。调用 Thread.Sleep(Timeout.Infinite) 将使线程休眠,直到它被调用 Thread.Interrupt 的另一个线程中断或被 Thread.Abort 中止为止。

还可以通过调用 Thread.Suspend 来暂停一个线程。当线程对其自身调用 Thread.Suspend 时,该调用将阻塞,直到该线程被另一个线程继续为止。当一个线程对另一个线程调用 Thread.Suspend 时,该调用就成为使另一个线程暂停的非阻塞调用。调用 Thread.Resume 将使另一个线程跳出挂起状态并使该线程继续执行,而与调用 Thread.Suspend 的次数无关。例如,如果连续调用 Thread.Suspend 五次,然后调用 Thread.Resume,则该线程将在对 Resume 的调用后面立即继续执行。

Thread.Sleep 不同,Thread.Suspend 不会使线程立即停止执行。公共语言运行库必须一直等待,直到线程到达安全点之后它才可以将该线程挂起。如果线程尚未启动或已经停止,则它将不能挂起。

SuspendResume 方法并不是对所有应用程序都有用,并且不应将其与同步机制混淆。由于 SuspendResume 不依赖于受控制线程的协作,因此它们具有高度侵犯性并会导致严重的应用程序问题,如死锁(例如,如果挂起的线程占有另一个线程需要的资源,就会发生这种情况)。某些应用程序确实需要控制线程的优先级以提高性能。为了做到这一点,应该使用 Thread.Priority 而不是 Thread.Suspend

可以使用许多方式来阻塞线程。例如,可以通过调用 Thread.Join 使一个线程等待另一个线程停止。可以使用 Monitor.Wait 使一个线程等待访问一个同步对象,还可以使用 Thread.Sleep 使该线程休眠。可以通过对被阻塞的线程调用 Thread.Interrupt 以引发 ThreadInterruptedException 来中断正在等待的线程,从而使该线程跳出阻塞调用。线程应捕获 ThreadInterruptedException 并执行适当的操作以继续工作。如果线程忽略该异常,则运行库将捕获该异常并停止该线程。

如果等待是托管等待,则 Thread.InterruptThread.Abort 都将立即唤醒线程。如果等待是非托管等待(例如对 Win32 WaitForSingleObject 函数的平台调用调用),则 InterruptAbort 都不能得到对该线程的控制,直到它返回到或调用到托管代码中为止。在托管代码中:

  • Thread.Interrupt 将线程从它可能处于的任何等待中唤醒,并在目标线程中引发 ThreadInterruptedException

  • Thread.Abort 类似于 Thread.Interrupt,除了它引发 ThreadAbortException 以外。该异常是一种特殊的异常,它不能从托管代码中捕获(尽管 finally 块被执行)。

销毁线程  [C#]

Thread.Abort 方法用于永久地停止逻辑线程。当调用 Abort 时,公共语言运行库将引发 ThreadAbortException。线程可以捕获该异常,但不能取消它。运行库将执行 catch 块和任何 finally 块,并且如果该线程是一个托管线程,系统将悄悄地停止该线程而不会通知用户。

由于 Thread.Abort 不会使线程立即中止,因此如果需要确保线程被停止,则必须调用 Thread.Join 以在该线程上等待。Join 是一个阻塞调用,该调用直到线程实际停止执行后才会返回。一旦线程被中止,它将无法重新启动。

您还可以调用 Thread.Join 并传递超时时间段。如果线程在超时结束之前死亡,该调用将返回 true。否则,如果该时间在线程死亡之前过期,则该调用将返回 false。在对 Thread.Join 的调用上等待的线程可以被调用 Thread.Interrupt 的其他线程中断。

ThreadAbortException

ThreadAbortException 可以在托管代码中的任何位置发生。但是,它们仅在具有足够特权的线程调用 Thread.Abort 或 AppDomain.Unload(其本身使用 Thread.Abort)时才发生。处理它们的最佳方式是具有足够的 finallycatch 子句,以便在您必须中途退出时维护一致的状态。必要时,引起 ThreadAbortException 的特权代码将捕获并重置它。

下面的 C# 代码示例不正确。

若要使前面的代码工作,您必须将附加的退出代码移到 catch 块中或将其放在 finally 块中。这是因为在进入 catch 块后,将由系统隐式重新引发 ThreadAbortException,而不管您在该块中对其进行了何种处理。换句话说就是,虽然您可以捕获 ThreadAbortException,但您不能取消它——它将根据需要被自动重新引发。显式取消其中一个异常的唯一方式是调用 Thread.ResetAbort,而这要求具有适当的特权。只有当您首先引起 ThreadAbortException 时,您才应执行此操作。

调度线程

每个线程都具有分配给它的线程优先级。在公共语言运行库中创建的线程最初分配的优先级为 ThreadPriority.Normal。在运行库以外创建的线程保留它们在进入托管环境之前具有的优先级。您可以使用 Thread.Priority 属性获取或设置任何线程的优先级。

线程是根据其优先级而调度执行的。即使线程正在运行库中执行,所有线程都是由操作系统分配处理器时间片的。用于确定线程执行顺序的调度算法的详细情况随每个操作系统的不同而不同。在某些操作系统下,具有最高优先级(相对于可执行线程而言)的线程经过调度后总是首先运行。如果具有相同优先级的多个线程都可用,则计划程序将遍历处于该优先级的线程,并为每个线程提供一个固定的时间片来执行。只要具有较高优先级的线程可以运行,具有较低优先级的线程就不会执行。如果在给定的优先级上不再有可运行的线程,则计划程序将移到下一个较低的优先级并在该优先级上调度线程以执行。如果具有较高优先级的线程可以运行,则具有较低优先级的线程将被抢先,并允许具有较高优先级的线程再次执行。除此之外,当应用程序的用户界面在前台和后台之间移动时,操作系统还可以动态调整线程优先级。其他操作系统可以选择使用不同的调度算法。

总结

    上面是VS.NET中.NET线程调用方面的基本概念和示例代码,整理出来给大家参考一下。有任何建议请MAIL我 paulni@citiz.net

 

在.NET中的线程处理(4)

Timer  [C#]计时器是使您能够指定要在指定时间调用的委托的轻量对象。线程池中的线程执行等待操作。使用 Timer 类是非常简单的。需要创建一个 Timer(通过将 TimerCallback ...
  • Paul_Ni
  • Paul_Ni
  • 2002年04月22日 09:38
  • 1146

在.NET中的线程处理(3)

使用异步 I/O 完成事件,线程池中的线程将只在收到数据时对数据进行处理,一旦处理完数据,该线程就会返回到线程池中。若要进行异步 I/O 调用,必须将操作系统 I/O 句柄与线程池相关联,并且必须指定...
  • Paul_Ni
  • Paul_Ni
  • 2002年04月22日 09:38
  • 1082

在.NET中的线程处理(1)

无论您是为具有单个处理器的计算机还是为具有多个处理器的计算机进行开发,您都希望应用程序为用户提供最好的响应性能,即使应用程序当前正在完成其他工作。要使应用程序能够快速响应用户操作,同时在用户事件之间或...
  • Paul_Ni
  • Paul_Ni
  • 2002年04月22日 09:39
  • 1808

在.NET中的线程处理(5)

Mutex  [C#]可以使用 Mutex 对象在线程之间以及跨进程进行同步。虽然 Mutex 不具备 Monitor 类的所有等待和脉冲功能,但它的确提供了创建可在进程之间使用的命名的互斥体的功能。...
  • Paul_Ni
  • Paul_Ni
  • 2002年04月22日 09:38
  • 1290

在.NET中的线程处理(2)

.NET 框架提供了许多有助于您创建和管理多线程应用程序的对象。WaitHandle 对象可以帮助您响应其他线程执行的操作,尤其是在与非托管代码交互操作时。ThreadPool 为大多数任务提供最佳的...
  • Paul_Ni
  • Paul_Ni
  • 2002年04月22日 09:39
  • 1284

.net 线程处理 托管线程处理的最佳做法

托管线程处理的最佳做法 发送反馈 多线程编程需要在编程时倍加注意。对于多数任务,通过将执行请求以线程池线程的方式排队,可以降低复杂性。本主题将探讨更复杂...
  • wuhenzhangxing
  • wuhenzhangxing
  • 2015年01月13日 11:40
  • 629

[.Net线程处理系列]专题二:线程池中的工作者线程

目录: 一、上节补充 二、CLR线程池基础 三、通过线程池的工作者线程实现异步 四、使用委托实现异步 五、任务 六、小结   一、上节补充 对于T...
  • gws1229
  • gws1229
  • 2014年01月16日 14:41
  • 840

Android中的线程处理

注:本文来自CSDN博主的一篇文章,个人觉得写得很好,值得借鉴,故收录在此 Android进程模型 在安装Android应用程序的时候,Android会为每个程序分配一个Lin...
  • DLUTBruceZhang
  • DLUTBruceZhang
  • 2013年02月09日 17:59
  • 2392

线程处理

  • zgqtxwd
  • zgqtxwd
  • 2008年04月24日 17:06
  • 133

.net使用线程与线程处理

1.线程的创建   .net是通过Thread类来描述线程的,线程的创建即构造Thread类即可。    Thread常用的构造函数有两个,分别是:   Thread(ThreadStart)  与 ...
  • peakwu
  • peakwu
  • 2008年10月26日 21:19
  • 420
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在.NET中的线程处理(6)
举报原因:
原因补充:

(最多只允许输入30个字)