使用Thread类创建线程

前面一段时间,一直在看<<C#高级编程>>第七版线程、任务和同步这一章的知识。创建线程,除了前面介绍的使用委托创建线程之外,创建线程的第二种方式是使用Thread类创建线程。

1.创建线程

使用Thread类可以创建和控制线程。下面的代码是创建和启动一个新线程的简单例子。

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Threading;
   6:  
   7: namespace Threading
   8: {
   9:     class Program
  10:     {
  11:       static void Main(string[] args)
  12:        {
  13:            //Thread类的构造函数重载为接受ThreadStart和ParameterizedThreadStart类型的委托参数
  14:            var t1 = new Thread(ThreadMain);
  15:            t1.Start();
  16:            Console.WriteLine("This is the main thread");
  17:        }
  18:        
  19:        //ThreadStart委托定义了一个返回类型为void的无参数方法
  20:        static void ThreadMain()
  21:        {
  22:            Console.WriteLine("running in a thread.");
  23:        }
  24:      }
  25: }

运行这个程序时,得到两个线程的输出:

image

不能保证哪个结果先输出,线程由操作系统调度,每次哪个线程在前面可以不同。

前面探讨了Lamda表达式如何与异步委托一起使用。Lamda表达式还可以与Thread类一起使用,将线程方法的实现代码传递给Thread构造函数的实参。

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Threading;
   6:  
   7: namespace Threading
   8: {
   9:     class Program
  10:     {
  11:          static void Main(string[] args)
  12:         {
  13:             var t1=new Thread(()=>Console.WriteLine("running in a thread,id:{0}",Thread.CurrentThread.ManagedThreadId));
  14:             t1.Start();
  15:             Console.WriteLine("This is the main thread,id:{0}",Thread.CurrentThread.ManagedThreadId);
  16:         }
  17:     }
  18: }

运行这个应用程序,现在可以看到线程名和ID。

image

 

2、给线程传递数据

     1)、使用带ParameterizedThreadStart委托参数给Thread构造函数。

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Threading;
   6:  
   7: namespace Threading
   8: {
   9:     class Program
  10:     {
  11:         //要给线程传递数据,需要某个存储数据的类或者结构。这里定义了包含字符串的Data结构,但可以传递任意对象
  12:         public struct Data
  13:         {
  14:            public string Message;
  15:         }
  16:         
  17:         //如果使用了ParameterizedThreadStart委托,线程的入口点必须有一个object类型的参数,且返回类型为void。对象可以强制转换为任意数据类型,这里是把消息写入控制台
  18:         static void ThreadMainWithParameters(object o)
  19:         {
  20:             Data d = (Data)o;
  21:             Console.WriteLine("running in a thread,receive {0}", d.Message);
  22:         }
  23:         static void Main(string[] args)
  24:         {
  25:             var d = new Data { Message = "info" };
  26:             //通过Thread类的构造函数,可以将新的入口点赋予ThreadMainWithParameters,传递变量d,以此调用Start()方法。
  27:             var t2 = new Thread(ThreadMainParameters);
  28:             t2.Start(d);
  29:         }
  30:     }
  31: }

运行结果如下所示:

image

 

   2)、定义一个类(参见MyThread类),在其中定义需要的字段,将线程的主方法定义为类的一个实例方法:

MyThead.cs:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: namespace Threading
   7: {
   8:     public class MyThead
   9:     {
  10:         private string data;
  11:  
  12:         public MyThead(string data)
  13:         {
  14:             this.data = data;
  15:         }
  16:         //定义成实例方法
  17:         public void ThreadMain()
  18:         {
  19:             Console.WriteLine("running in a thread,data:{0}",data);
  20:         }
  21:     }
  22: }

Program.cs:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Threading;
   6:  
   7: namespace Threading
   8: {
   9:     class Program
  10:     {
  11:         static void Main(string[] args)
  12:         {   //创建自定义类的实例
  13:             var obj = new MyThead("info");
  14:             //在Thread类的构造方法里面调用自定义类的实例方法
  15:             var t3 = new Thread(obj.ThreadMain);
  16:             t3.Start();
  17:         }
  18:     }
  19: }

运行结果如下所示:

image

 

3、后台线程

在默认情况下,用Thread类创建的线程是前台线程。线程池中的线程总是后台线程。在用Thread类创建线程时,可以设置IsBackground属性,以确认该线程是前台线程还是后台线程。Main()方法中将线程t1的IsBackground设置为false(默认值)。在启动新线程后,主线程就把结束消息写入控制台。新线程会写入启动消息和结束消息,在这个过程中它要休眠3秒,在这个过程中它要睡眠3秒,在新线程会完成其工作前,这3秒钟有利于主线程结束。

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Threading;
   6:  
   7: namespace Threading
   8: {
   9:     class Program
   10:     {
   11:         static void Main(string[] args)

12: {

  13:             var t1 = new Thread(ThreadMain)
  14:             {Name="MyNewThread",IsBackground=true };
  15:             t1.Start();
  16:             Console.ReadKey();
  17:         }
  18:         static void ThreadMain()
  19:         {
  20:             Console.WriteLine("Thread {0} started", Thread.CurrentThread.Name);
  21:             Thread.Sleep(3000);
  22:             Console.WriteLine("Thread {0} completed", Thread.CurrentThread.Name);
  23:         }
  24:     }
  25: }

运行结果如下所示:

image

 

如果将用来启动新线程的IsBackground属性改为true,显示在控制台上的结果就会不同。在控制台上,可以看到相同的结果-新线程的启动消息,但没有结束消息。如果线程没有正常结束,就也有可能看不到启动消息。原因是前台进程在主线程运行完毕后任然会运行,而后台在主线程运行完毕后会结束运行。

image

posted @ 2012-09-10 18:07  美梦成真  阅读(655)  评论(0编辑  收藏  举报