zoukankan      html  css  js  c++  java
  • C# 多线程六之Task(任务)二

    前面介绍了Task的由来,以及简单的使用,包括开启任务,处理任务的超时、异常、取消、以及如果获取任务的返回值,在回去返回值之后,立即唤起新的线程处理返回值、且如果前面的任务发生异常,唤起任务如果有效的处理异常等关于Task的知识。所以本文将介绍Task更多的用法和特性.

    一、如果通过一个任务创建多个子任务.

    1、Task支持一个任务,创建多个子任务,并且保持关联.

            static void Main(string[] args)
            {
                var parentTask = new Task<int[]>(() =>
                {
                    //开启多个子任务
                    var results = new int[2];
    
                    //创建子任务,并将子任务的值赋给results变量,并通过TaskCreationOptions.AttachedToParent,将其关联到父任务,如果不指定,该任务将独立于父任务单独执行
                    //这里有个奇怪的问题,只能使用new Task的方式去创建关联到父任务的子任务,因为Task.Run没有提供这个方法,可以通过扩展方法解决这个问题
                    new Task(() => results[0] = ChildThreadOne(), TaskCreationOptions.AttachedToParent).Start();
                    new Task(() => results[1] = ChildThreadTwo(), TaskCreationOptions.AttachedToParent).Start();
    
                    return results;
                });
                parentTask.Start();
                parentTask.ContinueWith(x =>
                {
                    Console.WriteLine("当父任务执行完毕时,CLR会唤起一个新线程,将父任务的返回值(子任务的返回值)输出,所以这里不会有任何的线程发生阻塞");
                    foreach (var re in parentTask.Result)
                    {
                        Console.WriteLine("子任务的返回值分别为:{0}", re);
                    }
                });
                Console.WriteLine("主线程不会阻塞,它会继续执行");
                Console.ReadKey();//必须加这行代码,因为Task时线程池线程,属于后台线程
            }
    
            /// <summary>
            /// 子任务一
            /// </summary>
            static int ChildThreadOne()
            {
                Thread.Sleep(2000);//模拟长时间计算操作
                Console.WriteLine("子任务一完成了计算任务,并返回值:{0}", 6);
                return 6;
            }
    
            /// <summary>
            /// 子任务一
            /// </summary>
            static int ChildThreadTwo()
            {
                Thread.Sleep(2000);//模拟长时间计算操作
                Console.WriteLine("子任务二完成了计算任务,并返回值:{0}", 6);
                return 6;
            }

    二、关于Task的资源释放问题.

    如果你看过Task的源码,你会发现下面这个有趣的问题:

    ok,你会想它想释放什么呢?

    没错,当Task任务,指定了TaskContinuationOptions枚举状态,且指定的值如下:

    那么,直接return,什么资源释放操作都不做.

    如果任务没有完成,就调用Dispose方法,那么直接抛异常,如果完成了,它就释放了ManualResetEventSlim信号量(后面的文章会介绍).所以如果你在task中使用了其它的一些非托管资源,那么最好在代码里自己手动释放,在使用完之后。或者自己实现了Task的派生类,把需要用的非托管资源加进去,然后在使用完派生类之后,调用Dispose方法.

    三、关于Task的几个常用属性

    1、Id属性,每个Task对象都有一个Id属性,全局唯一,且每次创建新的任务,这个值都会递增1.

    2、TaskStatus状态

        //
        // 摘要:
        //     表示 System.Threading.Tasks.Task 的生命周期中的当前阶段。
        public enum TaskStatus
        {
            //
            // 摘要:
            //     该任务已初始化,但尚未被计划。
            Created = 0,
            //
            // 摘要:
            //     该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。
            WaitingForActivation = 1,
            //
            // 摘要:
            //     该任务已被计划执行,但尚未开始执行。
            WaitingToRun = 2,
            //
            // 摘要:
            //     该任务正在运行,但尚未完成。
            Running = 3,
            //
            // 摘要:
            //     该任务已完成执行,正在隐式等待附加的子任务完成。
            WaitingForChildrenToComplete = 4,
            //
            // 摘要:
            //     已成功完成执行的任务。
            RanToCompletion = 5,
            //
            // 摘要:
            //     该任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;或者在该任务开始执行之前,已向该任务的
            //     CancellationToken 发出了信号。 有关详细信息,请参阅任务取消。
            Canceled = 6,
            //
            // 摘要:
            //     由于未处理异常的原因而完成的任务。
            Faulted = 7
        }

    构造完Task对象是,状态为Created,当任务启动时,状态变为WaitingToRun,当Task实际在线程上运行时,状态变为Running.如果当前任务为父任务,且它已经执行完毕,等待其它子任务执行完毕的时候,其状态变为WaitingForChildrenToComplete.如果任务完成可能会出现以下几种状态:RanToCompletion(已成功完成执行的任务)、Canceled(取消状态)、

    Faulted(任务出错).

    这里需要注意一个特殊的状态WaitingForActivation

    当使用Task对象的ContinueWith的Task对象处理改状态,意味者该Task任务的调度由任务基础结构控制.也就是该任务的调度只有当前面的任务执行完之后,由CLR发起执行调用.

  • 相关阅读:
    02注册Github账户
    软件工程概论第一节
    01课堂测试
    第二阶段冲刺01
    在子类中,若要调用父类中被覆盖的方法,可以使用super关键字
    动手动脑
    springBoot学习 错误记录
    什么是Hadoop?什么是HDFS?
    springCloud当中Eureca sever当中Camden到底是什么?
    Eureca Server的Helloworld例子
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/10051830.html
Copyright © 2011-2022 走看看