线程1

来源:互联网 发布:肖八肖四选择题 知乎 编辑:程序博客网 时间:2024/05/17 08:05

启动线程(Starting Threads)

创建一个线程的最简单的方法就是创建Thread类的一个新的实例。让Thread构造函数接受一个参数—— 一个委托实例。CLR专门为这种用途提供了ThreadStart委托类,它会指向你的一个方法。它允许你构造一个线程,然后告诉你:“当你启动的时候,就执行这个方法”。ThreadStart委托声明如下:

public delegate void ThreadStart();

正如你所看到的,你挂接到这个委托的方法必须不带参数,而且必须返回void。所以,你可能像一下代码这样去创建一个新的线程:

Thread myThread = new Thread(new ThreadStart(myFunc));

例如,你可能创建两个工作现场,一个从零开始计数:

         public void Incrementer()
        {
            for (int i = 0; i < 1000; i++)
            {
                System.Console.WriteLine("Incrementer :{0}",i);
            }
        }

另一个从1000往下计数

         public void Incrementer()
        {
            for (int i = 0; i < 1000; i++)
            {
                System.Console.WriteLine("Incrementer :{0}",i);
            }
        }

为了在线程中运行它们,创建两个新线程,每一个使用一个ThreadStart委托进行初始化。这些委托各自使用成员函数进行初始化:

Thread t1 = new Thread(new ThreadStart(Incrementer));

Thread t2 = new Thread(new ThreadStart(Decrementer));

实例化了这些线程并没有让它们开始运行。为了运行它们你必须调用这些线程对象的Start方法。

t1.Start();

t2.Start();

你需要对System.Threading加上using语句让编译器知道Thread类。注意输出,你可以看到处理器在t1和t2之间切换。

 

 class Program    {        static void Main(string[] args)        {            Program p = new Program();            Console.WriteLine("Hello");            //在静态方法Main()的外面执行它            p.DoTest();            Console.Read();        }        public void DoTest()        {             //为Incrementer创建一个线程,并传入一个ThreadStart委托            //地址是Incrementer方法            Thread t1 = new Thread(new ThreadStart(Incrementer));            //为Decrementer创建一个线程,并传入一个ThreadStart委托            //地址是Decrementer方法            Thread t2 = new Thread(new ThreadStart(Decrementer));            //启动这些线程            t1.Start();            t2.Start();        }        //演示函数,从上计数到1000        public void Incrementer()        {            for (int i = 0; i < 1000; i++)            {                 System.Console.WriteLine("Incrementer :{0}",i);            }        }        //演示函数,从1000向下计数        public void Decrementer()        {            for (int i = 1000; i >= 0; i--)            {                System.Console.WriteLine("Decrementer: {0}", i);            }        }    }


处理器允许一个线程执行一段时间直到向上计数到809为止。然后,第二个线程就会被执行,并且从60先下计数一段时间。然后,第一个线程又会 被允许执行。

 

拼接线程(连接线程)

当你暂停一个线程,让它等到另一个线程完成之后在继续,你是在把第一个线程拼接到第二个。相当于你把第一个的头部系到第二个的尾部,从而把它们拼接起来。

为了把线程1(t1)拼接到线程2(t2),写入代码:

t2.Join();

如果这个语句在线程t1的一个函数中运行,t1将会挂起等待,直到t2完成并且推出。例如你会需要Main()所在的线程等待所有其他的线程运行完毕,再打印它的结束信息。在下一个代码片断,假设你创建了一个线程集合名叫myThreads。遍历这个集合,一次把当前的线程拼接到集合中的线程:

foreah(Thread myThread in myThreads)

{

    myThread.Join();

}

Console.WriteLine("All my threads are done.");

最后一个消息“All my threads are done.” 直到所有的线程都运行完毕才会打印。在一个产品环境,你可能会建立一系列的线程完成某些任务(例如,打印、更新显示,等等),并且在这些工作线程都完成以前不想继续主线程的执行。

 使用Sleep方法阻塞线程(Blocking Threads With Sleep)

有时,你希望暂停你的线程一小会儿。例如,你可能希望你的时钟线程暂停大约1秒钟才去测试系统时间。这让你可以不用花费上亿个机器时钟周期,就可以大约1秒钟才去显示一次新的时间。

Thread类为这种用途提供了一个公共的静态方法Sleep()。这个方法由几种重载形式,其中一个版本接受一个 整数参数,另一个接受一个timeSpan对象。这两种类型的参数都表示的是你希望线程暂停的毫秒数目,只不过是通过一个int或一个timespan对象来表示。

 

销毁线程(Killing Thread)

通常,线程在执行完它们的任务之后会消亡。不过,你可以让线程销毁它自身。最简明的方法是设置一个KeepAlive的布尔标志,让线程定期去检查这个标志。当标志的状态变化(例如从true变到false)时,线程可以停止自己的执行。

另一种方法是调用Thread.Interrupt方法,这会通知线程销毁自己。最终,万不得已的时候,如果你不管怎样都必须关闭你的应用程序,就可以调用Thread.Abort。这会导致一个ThreadAbortException异常被抛出,而线程可以捕捉这一异常。