C#入门04:必点菜-线程和异步

线程

C#线程的生命周期分为几个阶段:
一、未启动状态:当线程实例被建立但 Start 方法未被调用时的情况;
二、就绪状态:当线程准备好运行并等待 CPU 周期时的情况;
三、不可运行状态:下面的几种状况下线程是不可运行的:
1). 已经调用 Sleep 方法;
2). 已经调用 Wait 方法;
3). 经过 I/O 操做阻塞。
四、死亡状态:当线程已完成执行或已停止时的情况。异步

一个简单的不带参数的线程:函数

//线程函数
    public static void Task()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Task Print {0}", i);
            Thread.Sleep(1000);
        }
    }

    //建立简单的线程,不带任何参数
    Thread th = new Thread(Task);
    th.Name = "PrintThread";

    //启动执行线程
    th.Start();

    //等待线程执行完毕
    th.Join();

    Console.WriteLine("Thread [{0}] Finished !", th.Name);

对于带参数的线程方法,一般须要自定义一个线程参数类,示例:线程

//自定义的线程参数类
    class ThreadParameter
    {
        private int size;

        public ThreadParameter(int s)
        {
            size = s;
        }

        //线程方法
        public void ThreadMethod()
        {
            for (int i = 0; i < size; i++)
            {
                Console.WriteLine("Task1 Print {0}", i);
                Thread.Sleep(1000);
            }
        }
    }

    //实例化线程参数类
    ThreadParameter tp = new ThreadParameter(10);

    //实例化线程对象
    Thread th = new Thread(tp.ThreadMethod);
    th.Name = "PrintThread";

    //启动线程
    th.Start();

    //等待线程结束
    th.Join();

    Console.WriteLine("Thread [{0}] Finished !", th.Name);

Abort() 方法用于销毁线程。经过抛出 threadabortexception 在运行时停止线程。这个异常不能被捕获,若是有 finally 块,控制会被送至 finally 块。code

public static void ThreadProc()
    {
        try
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Task1 Print {0}", i);
                Thread.Sleep(1000);
            }
        }
        //捕获线程异常退出
        catch (ThreadAbortException e)
        {
            Console.WriteLine(e);
        }
        finally
        {
            Console.WriteLine("Thread Finished !");
        }
    }

    //实例化线程对象
    Thread th = new Thread(ThreadProc);

    //启动线程
    th.Start();

    //等待5秒后结束线程
    Thread.Sleep(5000);
    th.Abort();

    Console.WriteLine("Thread [{0}] Finished !", th.Name);

异步

有时候一个函数的执行很长,不能一直等待函数执行完毕,但愿在函数执行的时候主线程能够完成些其余的事情,而后再等待线程执行完毕。下面的代码同步执行时会依次打印1~5数字,而异步执行的时候则是乱序的:orm

static void Test(string name)
    {
        Console.WriteLine("TestMethod: {0:yyyy-MM-dd HH:mm:ss.fff} {1}", DateTime.Now, name);
    }

    static void Main()
    {
        TestDelegate d = Test;
        Console.WriteLine("Beginning : {0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now);

        //同步执行,依次打印
        d("111");
        d("222");
        d("333");
        d("444");
        d("555");

        //异步执行,会放入线程池中,打印乱序
        var r1 = d.BeginInvoke("小明1", null, null);
        var r2 = d.BeginInvoke("小明2", null, null);
        var r3 = d.BeginInvoke("小明3", null, null);
        var r4 = d.BeginInvoke("小明4", null, null);
        var r5 = d.BeginInvoke("小明5", null, null);

        //此时异步执行尚未完成
        Console.WriteLine("End       : {0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now);

        //等待异步执行完成
        d.EndInvoke(r1);
        d.EndInvoke(r2);
        d.EndInvoke(r3);
        d.EndInvoke(r4);
        d.EndInvoke(r5);

        Console.WriteLine("线程所有执行完成");
            
        Console.Read();
    }

另一个定时器定时打印的例子:对象

//打印当前日期和时间
    static void PrintPoint(object sender, ElapsedEventArgs e)
    {
        DateTime dtCurr = DateTime.Now;
        Console.WriteLine("{0:yyyy-MM-dd HH:mm:ss.fff}", dtCurr);
        Thread.Sleep(1000);
    }

    static void Main()
    {
        //构建定时器,
        System.Timers.Timer timer = new System.Timers.Timer();
        timer.Interval = 1000;
        timer.Start();

        //链接打印方式到定时器超时事件
        timer.Elapsed += new ElapsedEventHandler(PrintPoint);

        Console.WriteLine("End");
        Console.Read();
    }

在主线程中使用EndInvoke仍是很麻烦,始终要阻塞等待。使用异步回调就能够解决这个问题,当异步返回时自动调用回调函数:生命周期

//异步结束时的回调
    public static void BackCall(IAsyncResult parameter)
    {
        //parameter.IsCompleted用于判断异步方法是否已调用完成;
        if (parameter.IsCompleted)
        {
            //经过EndInvoke方法获取异步方法的返回结果(类型与异步方法的结果一致)      
            Console.Write(string.Format("回调完成,返回值"));
        }
        else
        {
            Console.Write("调用未完成");
        }
    }

    TestDelegate td = PrintPoint;
    td.BeginInvoke(BackCall, null);

    Console.WriteLine("End");
    Console.Read();
相关文章
相关标签/搜索