当前位置:嗨网首页>书籍在线阅读

08-结束线程

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

21.2.3 结束线程

在C#中,System.Threading命名空间提供了一些可以进行多线程编程的类和接口。除了同步线程活动和数据访问的类之外,此命名空间还包含一个 ThreadPool 类,它使用户能够使用系统提供的线程池和一个 Timer 类,在线程池线程上执行回调方法。Thread类有几个重要的方法,描述如下。

  • Abort():调用此方法通常会终止线程。在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。
  • Sleep(int):已重载。 将当前线程阻塞指定的毫秒数。该方法是静态方法。
  • Suspend():该方法并不终止未完成的线程,它仅仅挂起线程,以后还可恢复。
  • Resume():恢复被Suspend()方法挂起的线程的执行 。

下面动手编写一个完整线程操作的例子,进行创建线程、运行线程、终止线程的全程操作。

【范例21-6】 C#中的线程程序。

(1)在Visual C#窗口中选择【新建】 【项目】,弹出【新建项目】对话框,在【模板】中选择【控制台应用程序】,在【名称】文本框中输入项目名称“SubThread”。

(2)单击【确定】按钮,直接打开“Program.cs”的代码窗口,然后在“Program.cs”中的program类中输入以下代码(代码21-6-1.txt)。

01  public class SubThread
02  {
03          public void SubThreadFunc()               //定义线程方法SubThreadFunc
04          {
05                  int i;                            //定义整型变量i
06                  i = 0;                            //变量i赋初值
07                  do                                //do循环开始
08                          {
09                                  i = i + 1;        //i变量增加1
10                                  Console.WriteLine("子线程正在运行……{0}", i);   //输出当前线程状态
11                          }
12                  while (1 == 1);                  //特意编写的无限循环
13          }
14  };
**注意** C#不会自动添加对命名空间Threading的引用,用户需要添加“using System.Threading;”完成对线程命名空间的引用。

这段程序定义了一个非常简单的类SubThread,在这个类中仅有一个方法:SubThreadFunc。当这个方法被调用时,只要没有外界的干扰,将会一直输出:“子线程正在运行……”。如果没有线程,我们就没有一个非常好的办法在程序内部中断这种类型的循环,而线程则给我们提供了一种非常完美的方式。

(3)在“Program.cs”中的Main方法中输入以下代码(代码21-6-2.txt)。

01  //输出演示程序的用意
02  Console.WriteLine("子线程启动、停止、终止、阻塞综合演示:");
03  //创建线程ThreadS,演示SubThread类的SubThreadFunc()方法
04  SubThread SThread = new SubThread();            
05  Thread ThreadS = new Thread(new ThreadStart(SThread.SubThreadFunc));
06  //输出启动线程
07  Console.WriteLine("子线程启动---------------------;");
08  //启动线程
09  ThreadS.Start();
10  //输出子线程状态
11  Console.WriteLine("子线程状态---------------------{0};", ThreadS.ThreadState);
12  //主线程睡眠1毫秒
13  Thread.Sleep(1);
14  Console.WriteLine("主线程睡眠1毫秒;");
15   //ThreadS终止
16  ThreadS.Abort();
17  //输出线程状态
18  Console.WriteLine();
19  Console.WriteLine("子线程状态---------------------{0};", ThreadS.ThreadState);
20  Console.WriteLine("子线程终止---------------------;");
21  Console.WriteLine("SThread.SubThreadFunc 被终止。");
22  //启动线程,并捕获错误
23  try
24  {
25          ThreadS.Start();
26          Console.WriteLine("尝试启动SThread.SubThreadFunc 线程"); 
27  }
28  catch (ThreadStateException)
29  {
30          //当出现启动错误时,显示错误提示
31          Console.WriteLine("SThread.SubThreadFunc已经中止线程不能被重新启动。");
32          Console.ReadLine();
33  }
34  return;        //返回

【范例分析】

此范例中最关键的代码是步骤(3)中的代码,首先,使用语句“ThreadS.Start();”启动子程序,这个时候,语句“Thread.Sleep(1);”使得主程序休眠1毫秒,给子线程留出运行时间,然后使用语句“ThreadS.Abort();”终止子线程的运行,从而有效地避免了程序无限制地停留在一段无限循环的程序段中。线程为我们提供了一种很好的控制子程序的方法。

在范例中,我们还演示了一个已经被Abort()终止的线程能否被重新启动,在范例运行后的结果中已经看到,一个被终止的线程是不能被重新启动的。在这段程序中为了对我们已经学习到的知识进行扩展,程序中还有意使用了Thread.ThreadState属性,这个属性代表了线程运行时的状态,指示当前线程的状态的枚举值之一,ThreadState 为线程定义了一组所有可能的执行状态。一旦线程被创建,它就至少处于其中的一个状态中,直到终止。在公共语言运行中创建的线程最初处于 Unstarted状态,而进入运行时的外部线程则已经处于 Running 状态。通过调用 Start 方法,可以将 Unstarted 线程转换为 Running 状态。并非所有的 ThreadState 值的组合都是有效的,例如,线程不能同时处于 Aborted 和 Unstarted 状态中。 ThreadState在各种情况下的可能取值如下表所示。

| 成员名称 | 说明 | | :----- | :----- | :----- | :----- | | Running | 线程已启动,它未被阻塞,并且没有挂起的 ThreadAbortException | | StopRequested | 正在请求线程停止。这仅用于内部 | | SuspendRequested | 该线程已被标记为挂起 | | Background | 线程正作为后台线程执行(相对于前台线程而言)。此状态可以通过设置 Thread.IsBackground 属性来控制 | | Unstarted | 尚未对线程调用 Thread.Start 方法 | | Stopped | 线程已停止 | | WaitSleepJoin | 线程已被阻止。这可能是因为调用 Thread.Sleep 或Thread.Join、请求锁定(例如,通过调用Monitor.Enter或 Monitor.Wait)或等待线程同步对象(如 ManualResetEvent) | | Suspended | 线程已挂起 | | AbortRequested | 已对线程调用了 Thread.Abort方法,但线程尚未收到试图终止它的挂起的 System.Threading.ThreadAbortException | | Aborted | 线程状态包括 AbortRequested,并且该线程现在已死,但其状态尚未更改为 Stopped |

【运行结果】

按【Ctrl+F5】组合键不调试直接运行程序,则会弹出控制台窗口,显示类似如下图所示的执行结果。

372.png 【拓展训练】

如果子线程想运行更长的时间,我们可以把语句“Thread.Sleep(1);”改为“Thread.Sleep(200);”或者是更大的数值,对相应的注释也可以做相应的修改,这样在运行程序之后,就可以看到子线程明显获得了更长的运行时间。部分代码如下(拓展代码21-6-3.txt)。

01  Console.WriteLine("子线程启动、停止、终止、阻塞综合演示:");            
02  SubThread SThread = new SubThread();
03  Thread ThreadS = new Thread(new ThreadStart(SThread.SubThreadFunc));
04  ThreadS.Start();
05  Console.WriteLine("子线程状态---------------------{0};", ThreadS.ThreadState);
06  Thread.Sleep(200);                //主线程睡眠200毫秒