zoukankan      html  css  js  c++  java
  • .Net多线程编程—任务Task

    1 System.Threading.Tasks.Task简介

    一个Task表示一个异步操作,Task的创建和执行是独立的。

    只读属性:

    返回值

    名称

    说明

    object

    AsyncState

    表示在创建任务时传递给该任务的状态数据

    TaskCreationOptions

    CreationOptions

    获取用于创建此任务的 TaskCreationOptions

    CurrentId

    当前正在执行 Task 的 ID

    AggregateException

    Exception

    获取导致 AggregateException 提前结束的 Task。如果 Task 成功完成或尚未引发任何异常,则返回 null

    TaskFactory

    Factory

    提供对用于创建 Task 和 Task<TResult> 的工厂方法的访问

    int

    Id

    获取此 Task 实例的 ID

    bool

    IsCanceled

    指明此 Task 实例是否由于被取消的原因而已完成执行

    bool

    IsCompleted

    指明此 Task 是否已完成

    bool

    IsFaulted

    指明Task 是否由于未经处理异常的原因而完成

    TaskStatus

    Status

    获取此任务的 TaskStatus

    2 Task状态和生命周期

    一个Task实例只会完成其生命周期一次,当Task达到它的3种可能的最终状态之一时,它就再也回不去之前的状态了。任务的生命周期从TaskStatus.Created状态真正开始。

    1) 初始状态

    Task实例有三种可能的初始状态

    说明

    TaskStatus.Created

    该任务已初始化,但尚未被计划。使用Task构造函数创建Task实例时的初始状态。

    TaskStatus.WaitingForActivation

    该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。一个任务的初始状态,这个任务只有当其依赖的任务完成之后才会被调度。

    TaskStatus.WaitingToRun

    该任务已被计划执行,但尚未开始执行。使用TaskFactory.StartNew创建的任务的初始状态。

    2)中间状态

    Task实例有两种可能的中间状态

    说明

    TaskStatus.Running

    该任务正在运行,但尚未完成

    TaskStatus.WaitingForChildrenToComplete

    该任务已完成执行,正在隐式等待附加的子任务完成

    3) 最终状态

    Task实例有三种可能的最终状态

    说明

    TaskStatus.Canceled

    该任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;或者在该任务开始执行之前,已向该任务的 CancellationToken 发出了信号。Task属性IsFaulted被设置为true

    TaskStatus.Faulted

    由于未处理异常的原因而完成的任务。Task属性IsCanceled被设置为true

    TaskStatus.RunToCompletion

    已成功完成执行的任务。Task属性IsCompleted被设置为trueIsFaultedIsCanceled被设置为false

     

    3 创建并执行任务

    1)public Task StartNew(Action action)

    参数:

      action:要异步执行的操作委托

    返回值:

      已启动的 System.Threading.Tasks.Task

    异常:

      System.ArgumentNullException:当 action 参数为 null 时引发的异常。

    2)public static Task Run(Action action)

    参数:

      action:表示在线程池执行的队列的任务

    返回值:

      已启动的 System.Threading.Tasks.Task

    异常:

      System.ArgumentNullException:当 action 参数为 null 时引发的异常。

    3)public void Start()

    启动 System.Threading.Tasks.Task,并将它安排到当前的 System.Threading.Tasks.TaskScheduler中执行。

    异常:

      System.ObjectDisposedException:已释放 System.Threading.Tasks.Task 实例。

      System.InvalidOperationExceptionSystem.Threading.Tasks.Task 未处于有效状态,无法启动。 它可能已启动、已执行或已取消,或者可能已经不支持以直接计划的方式创建。

    注意:

      仅使用Task的构造器来创建Task的实例并不能启动任务,还要使用Start才能启动任务。

    4)Task.Factory.StartNewTask.Run

    Task.Factory.StartNew重载方法提供更多的参数,可以控制如何计划执行任务以及如何向调试器公开计划任务的机制和控制任务的创建和执行的可选行为。

    而Task.Run提供的方法则不具有上述控制机制。

    4 等待任务完成

    1)public void Wait()

    等待 System.Threading.Tasks.Task 完成执行过程

    异常:

      ObjectDisposedException:Task 对象已被释放。

      AggregateExceptionSystem.Threading.Tasks.Task 已取消或在 System.Threading.Tasks.Task 的执行期间引发了异常。如果任务已被取消,System.AggregateException将包含其 System.AggregateException.InnerExceptions 集合中的 System.OperationCanceledException

    2public static void WaitAll(params Task[] tasks)

    参数:

      tasks:要等待的 Task 实例的数组

    异常:

      ObjectDisposedException:一个或多个 Task 中的对象 tasks 已被释放。

      ArgumentNullExceptiontasks 参数为 nulltasks 参数包含 null 元素。

      AggregateException:在至少一个 Task 实例已取消。如果任务已被消, AggregateException 异常包含 OperationCanceledException 中的异常其   AggregateException.InnerExceptions 集合。或在至少一个执行期间引发了异常 Task 实例。

    说明:

      主线程会等待作为参数传入的任务tasks执行结束才会执行下一条语句。

    3)public static int WaitAny(params Task[] tasks)

    参数:

      tasks:要等待的 Task 实例的数组

    异常:

      System.ObjectDisposedExceptionSystem.Threading.Tasks.Task 已被释放。

      System.ArgumentNullExceptiontasks 参数为 null

      System.ArgumentExceptiontasks 参数包含 null 元素。

    5 取消任务

    使用System.Threading.CancellationToken和System.Threading.CancellationTokenSource中断Task的执行。

    1)System.Threading.CancellationToken

    传播有关应取消操作的通知

    属性:

      public bool IsCancellationRequested { get; }

    方法

      public void ThrowIfCancellationRequested();

      如果已请求取消此标记,则引发 System.OperationCanceledException。

    异常:

      System.OperationCanceledException:该标记已请求取消。

          System.ObjectDisposedException:关联的System.Threading.CancellationTokenSource已被释放。

    2) System.Threading.CancellationTokenSource

    通知 System.Threading.CancellationToken,告知其应被取消

    属性:

      public CancellationToken Token { get; }:获取与此 System.Threading.CancellationTokenSource 关联的 System.Threading.CancellationToken。

    异常:

      System.ObjectDisposedException:已释放标记源。

    方法:

      public void Cancel():传达取消请求。

    异常:

      System.ObjectDisposedException: System.Threading.CancellationTokenSource 已被释放。

      System.AggregateException:聚合异常包含由相关联的 System.Threading.CancellationToken 上已注册的回调引发的所有异常。

    6 任务的返回值

    1)Task类型

    在第1节中已经介绍了Task

    2)Task<TResult>类型

    属性

    定义

    说明

    public static TaskFactory<TResult> Factory { get; }

    提供对用于创建 System.Threading.Tasks.Task<TResult> 实例的工厂方法的访问。

    public TResult Result { get; }

    获取此 System.Threading.Tasks.Task<TResult> 的结果值

    方法

      public Task ContinueWith(Action<Task<TResult>> continuationAction)

    参数:

      continuationAction:在 System.Threading.Tasks.Task<TResult> 完成时要运行的操作。在运行时,委托将作为一个参数传递给完成的任务。

    异常:

      System.ObjectDisposedException:System.Threading.Tasks.Task<TResult> 已被释放。

      System.ArgumentNullException:continuationAction 参数为 null。

    注意:

    • 该方法的重载方法提供了更多的控制机制。可以传入CancellationTokenTaskContinuationOptionsTaskScheduler参数。
    • 使用Task.Factory.StartNew方法,如果传入的委托无返回值,那么方法执行的返回结果类型其实是Task<TResult>,通过Task<TResult>类型的Result 属性可以查看返回结果。对于串联的多个任务,若后续的任务要使用上一个任务的结果,那么Task.Factory.StartNew返回值类型必须是Task<TResult>var
    • 返回值可以是自定义类型。

    7 TaskCreationOptions (枚举类型)

    用途:控制任务创建与执行的行为。

    说明

    TaskCreationOptions.None

    指定应使用默认行为

    TaskCreationOptions.PreferFairness

    提示 System.Threading.Tasks.TaskScheduler 以一种尽可 能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行

    TaskCreationOptions.LongRunning

    指定某个任务将是运行时间长、粗粒度的操作。 它会向 System.Threading.Tasks.TaskScheduler 提示,过度订阅可能是合理的。

    TaskCreationOptions.AttachedToParent

    指定将任务附加到任务层次结构中的某个父级

    TaskCreationOptions.DenyChildAttach

    如果尝试附有子任务到创建的任务,指定 System.InvalidOperationException 将被引发

    TaskCreationOptions.HideScheduler

    防止环境计划程序被视为已创建任务的当前计划程序。 这意味着像 StartNew 或 ContinueWith 创建任务的执行操作将被视为 System.Threading.Tasks.TaskScheduler.Default当前计划程序

    8 任务计划TaskScheduler

    功能:扩展任务执行计划,例如自定义任务计划程序来实现性能加速。

    属性:

    名称

    说明

    Current

    当前正在执行的任务关联的 TaskScheduler

    Id

    TaskScheduler 的唯一 ID

    MaximumConcurrencyLevel

    指示此 TaskScheduler 能够支持的最大并发级别

     

    9 串联多个任务

    1public Task ContinueWith(Action<Task> continuationAction);

    参数:

      continuationAction:在 System.Threading.Tasks.Task 完成时要运行的操作。 在运行时,委托将作为一个参数传递给完成的任务。

    异常:

      System.ObjectDisposedException:创建了 cancellationToken System.Threading.CancellationTokenSource 已经被释放。

      System.ArgumentNullExceptioncontinuationAction 参数为 null

    2public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions);

    参数:

      continuationAction:根据在 continuationOptions 中指定的条件运行的操作。 在运行时,委托将作为一个参数传递给完成的任务。

      continuationOptions:用于设置计划延续任务的时间以及延续任务的工作方式的选项。

    3TaskContinuationOptions

    enum类型,用于设置计划延续任务的时间以及延续任务的工作方式的选项。 这包括条件(如 System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled)和执行选项(如

    System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously)。

    说明

    ContinuationOptions.None

    指定应使用默认行为。默认情况下,完成前面的任务之后将安排运行延续任务,而不考虑前面任务的最终 System.Threading.Tasks.TaskStatus

    ContinuationOptions.LongRunning

    指定某个任务将是运行时间长、粗粒度的操作。 它会向 System.Threading.Tasks.TaskScheduler 提示,过度订阅可能是合理的。

    ContinuationOptions.AttachedToParent

    指定将任务附加到任务层次结构中的某个父级。

    ContinuationOptions.DenyChildAttach

    如果尝试附有子任务到创建的任务,指定 System.InvalidOperationException 将被引发。

    ContinuationOptions.HideScheduler

    防止环境计划程序被视为已创建任务的当前计划程序。 这意味着像 StartNew ContinueWith 创建任务的执行操作将被视为System.Threading.Tasks.TaskScheduler.Default当前计划程序。

    ContinuationOptions.LazyCancellation

    在延续取消的情况下,防止延续的完成直到完成先前的任务

    ContinuationOptions.NotOnRanToCompletion

    指定不应在延续任务前面的任务已完成运行的情况下安排延续任务。 此选项对多任务延续无效

    ContinuationOptions.NotOnFaulted

    指定不应在延续任务前面的任务引发了未处理异常的情况下安排延续任务。 此选项对多任务延续无效

    ContinuationOptions.OnlyOnCanceled

    指定只应在延续任务前面的任务已取消的情况下才安排延续任务。 此选项对多任务延续无效

    ContinuationOptions.NotOnCanceled

    指定不应在延续任务前面的任务已取消的情况下安排延续任务。 此选项对多任务延续无效

    ContinuationOptions.OnlyOnFaulted

    指定只应在延续任务前面的任务引发了未处理异常的情况下才安排延续任务。 此选项对多任务延续无效

    ContinuationOptions.OnlyOnRanToCompletion

    指定只应在延续任务前面的任务已完成运行的情况下才安排延续任务。 此选项对多任务延续无效

    ContinuationOptions.ExecuteSynchronously

    指定应同步执行延续任务。 指定此选项后,延续任务将在导致前面的任务转换为其最终状态的相同线程上运行。 如果在创建延续任务时已经完成前面的任务,则延续任务将在创建此延续任务的线程上运行。只应同步执行运行时间非常短的延续任务

    ContinuationOptions.PreferFairness

    提示 System.Threading.Tasks.TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。

    注意:

    1)可以通过位操作组合使用多个值。

    2)使用ContinuationOptions.None意味着不论前面的任务是否被取消,延续任务都会执行。

    异常:

      System.ObjectDisposedExceptionSystem.Threading.Tasks.Task 已被释放。

      System.ArgumentNullExceptioncontinuationAction 参数为 null

      System.ArgumentOutOfRangeExceptioncontinuationOptions 参数为 System.Threading.Tasks.TaskContinuationOptions 指定无效值。

    3)子任务(嵌套任务):在父任务的委托中创建的 System.Threading.Tasks.Task 实例。 子任务包括两种:附加的子任务与分离的子任务

    • 分离的子任务是不依赖于其父级而执行。
    • 附加的子任务是使用 TaskCreationOptions.AttachedToParent 选项创建的,依赖于其父任务而执行。 对父任务使用TaskCreationOptions.DenyChildAttach来阻止子任务附加到父任务。
    • 一个任务可以创建任意数量的附加的子任务和分离的子任务,这仅受系统资源限制。
    • 不提倡创建附加的子任务,这样会大大增加程序设计的复杂性。

    10 使用模式

    1)创建任务

    基本形式:

     1 private void CreatTask()
     2 {
     3     //创建并执行任务
     4     Task task = new Task(() =>
     5     {
     6         //具体操作
     7     });
     8     task.Start();
     9 
    10     //创建并将任务加入执行计划,使用StartNew
    11     Task.Factory.StartNew(() => {
    12         //具体操作
    13     });
    14 
    15     //创建并将任务加入执行计划,使用Run
    16     Task.Run(() =>
    17     {
    18         //具体操作
    19     });
    20 
    21     //安排任务
    22     Task.Factory.StartNew(() =>
    23     {
    24         //具体操作
    25     },TaskCreationOptions.PreferFairness);
    26 }    

    创建附加的子任务:

     1 private void CreateTask_Parent()
     2 {
     3     //附加子任务
     4     var taskParent = Task.Factory.StartNew(() =>
     5     {
     6         //操作......
     7         var child = Task.Factory.StartNew(() =>
     8         {
     9             //具体操作
    10         }, TaskCreationOptions.AttachedToParent);
    11     });
    12     taskParent.Wait();
    13 
    14 
    15     //阻止附加子任务
    16     var taskParentZ = Task.Factory.StartNew(() =>
    17     {
    18         //操作......
    19         var child = Task.Factory.StartNew(() =>
    20         {
    21             //即使设置TaskCreationOptions.AttachedToParent也无法将其附加到父任务
    22             //具体操作
    23         }, TaskCreationOptions.AttachedToParent);
    24     }, TaskCreationOptions.DenyChildAttach);
    25     taskParentZ .Wait();
    26 }    

    2)取消任务

     1 public static void CancelFromExternal_Task()
     2 {
     3     CancellationTokenSource cts = new CancellationTokenSource();
     4 
     5     //其他操作...
     6 
     7     //计算condition
     8     bool condition = ...;
     9     if (condition) cts.Cancel();
    10     //或使用Operation2_Task(cts);
    11     Operation1_Task(cts);
    12     //其他操作...
    13 
    14 }
    15 
    16     //1 使用IsCancellationRequested属性
    17     private static void Operation1_Task(CancellationTokenSource cts)
    18     {
    19         CancellationToken ct = cts.Token;
    20         Task.Factory.StartNew(() => 
    21         {
    22             //其他操作...
    23             //return只对当前子线程有效
    24             if (ct.IsCancellationRequested)
    25             { return; }
    26             //其他操作...
    27         },ct);     
    28     }
    29 
    30     //2 使用抛异常的方式
    31     private static void Operation2_Task(CancellationTokenSource     cts)
    32     {
    33         CancellationToken ct = cts.Token; 
    34         Task.Factory.StartNew(() =>
    35         {
    36             //其他操作...
    37             ct.ThrowIfCancellationRequested();
    38             //其他操作...
    39         }, ct);
    40     }    

    3)等待任务完成

     1 private void WaitFunc()
     2 {
     3     Task task = new Task(() => 
     4     {
     5         //具体操作
     6     });
     7     task.Start();
     8     task.Wait();
     9 }
    10 
    11 private void WaitAllFunc()
    12 {
    13     Task task1 = Task.Run(() =>
    14     {
    15         //具体操作 
    16     });
    17     Task task2 = Task.Run(() =>
    18     {
    19         //具体操作 
    20     });
    21     //等待task1与task2,直到它们完成为止
    22     Task.WaitAll(task1, task2);
    23 
    24     //等待task1与task2,如果超过1000毫秒则返回。
    25     Task.WaitAll(new Task[] { task1, task2 },1000);
    26 }

    4)串联多个任务

     1 private void contactTasks()
     2 {
     3     var t1 = Task.Factory.StartNew(() =>
     4     {
     5         //具体操作1
     6         //return 返回值;
     7     });
     8 
     9     var t2 = t1.ContinueWith((t) =>
    10     {
    11         //具体操作2
    12         //return 返回值;
    13     });
    14 
    15     var t3 = t2.ContinueWith((t) =>
    16     {
    17         //具体操作3
    18     });
    19 
    20     var t4 = t1.ContinueWith((t) =>
    21     {
    22         //具体操作4
    23     });
    24 
    25     var t5 = t1.ContinueWith((t) =>
    26     {
    27         //具体操作5
    28     });
    29 
    30     Task.WaitAll(t3, t4, t5);
    31 }

    -----------------------------------------------------------------------------------------

    转载与引用请注明出处。

    时间仓促,水平有限,如有不当之处,欢迎指正。

  • 相关阅读:
    (笔记)Linux内核学习(二)之进程
    (笔记)Linux内核学习(一)之内核介绍
    状态机思路在程序设计中的应用
    内存操作函数memmove,memcpy,memset
    linux下常用的几个时间函数:time,gettimeofday,clock_gettime,_ftime
    Camera ISO、快门、光圈、曝光这几个概念
    C语言中的指针和内存泄漏几种情况
    音视频文件码率与大小计算
    CC++中 fopen中文件打开方式的区别:
    常用DOS命令
  • 原文地址:https://www.cnblogs.com/hdwgxz/p/6159714.html
Copyright © 2011-2022 走看看