zoukankan      html  css  js  c++  java
  • 多线程编程学习笔记——任务并行库(三)

    接上文 多线程编程学习笔记——任务并行库(一)

    接上文 多线程编程学习笔记——任务并行库(二)

    六、   实现取消选项

              本示例学习如何实现基于Task的异步操作进行取消流程,以及在任务真正运行前如何知道任务已经被取消。

    1.代码如下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks; 
    
    namespace ThreadTPLDemo
    {   
    
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(" 将Task中实现取消操作。。。");
                var cts =new CancellationTokenSource();
    
                var task1 = new Task<int>(() => RunTask("任务 1",10, cts.Token),cts.Token);     
    
                         Console.WriteLine(" ——task1 状态—{0}", task1.Status);
    
                cts.Cancel();
                         Console.WriteLine(" ——取消——task1 状态—{0}—",task1.Status);            
    
                         Console.WriteLine(" ——task1 在出错之前 取消了操作—");
    
                //task1.Start();
                cts = new CancellationTokenSource();
                var task2 = new Task<int>(() => RunTask("任务 2", 10, cts.Token),cts.Token);
                task2.Start();
                for (int i = 0; i < 5; i++)
                {
    
                    Thread.Sleep(500);
                    Console.WriteLine(" ——task2 状态—{0}", task2.Status);
                }
    
                cts.Cancel();
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(500); 
                    Console.WriteLine(" ——task2 状态—{0}", task2.Status);
    
                }
                Console.WriteLine(" ——任务Task 运行结果—{0}", task2.Result);
                Thread.Sleep(2000);      
                Console.Read(); 
    
            }
     
    
            private static int RunTask(string name,int seconds,CancellationToken token)
            {      
    
                Console.WriteLine("Task {0}  运行在线程={1}中,是否在线程池 :{2}",name,
    Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread);
    for (int i = 0; i < seconds; i++) { Thread.Sleep(TimeSpan.FromSeconds(1)); if (token.IsCancellationRequested) { //取消操作,返回-1; return -1; } } return 42 * seconds; } } }

    2.程序运行结果如下图。


          首先我们来看task1的创建代码,我们给底层任务传递一次取消标志,然后给任务的构造函数又传递了一次。

          那为什么要传递两次取消标志呢?

          因为如果在task实际启动之前取消它,则TPL的底层有责任处理这个取消操作。经过TPL底层处理过取消操作的task,如果再次启动,则会抛出异常。如下图。

     

     

             然后需要我们自己写代码处理取消操作,在取消操作之后,任务的状态仍然是RanToCompletion,从TPL来角度来讲,这个task已经完成。

    七、   处理task中的异常

              通过此示例我们学习如何在task中抛出不同情况的异常,以及如何获取这些异常信息。

     1.程序代码如下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
     
    
    namespace ThreadTPLDemo
    {
    
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(" 处理Task中的异常信息。。。。。");
                try
                {
                    var task1 = Task.Run(() => RunTask("任务 1", 2));
    
                    int result = task1.Result;
                    Console.WriteLine(" ——task1 状态—{0}---值=={1}", task1.Status,result);
                }
                catch (Exception ex)
                {
    
                    Console.WriteLine(" ——task1 错误信息—{0};innerException--{1}", ex.Message,
    ex.InnerException==null?string.Empty:ex.InnerException.Message); } Console.WriteLine(" ——————————————————————"); try { var task2 = Task.Run(() => RunTask("任务 2", 2)); int result = task2.GetAwaiter().GetResult(); Console.WriteLine(" ——task2 状态—{0}---值=={1}", task2.Status, result); } catch (Exception ex) { Console.WriteLine(" ——task2 错误信息—{0}", ex.Message); } Console.WriteLine(" ——————————————————————"); var task3 = new Task<int>(() => RunTask("任务 3", 2)); var task4 = new Task<int>(() => RunTask("任务 4", 2)); var completeTaskAll = Task.WhenAll(task3, task4); var exception = completeTaskAll.ContinueWith(t => Console.WriteLine(" ——task 错误信息—{0}", t.Exception)
    , TaskContinuationOptions.OnlyOnFaulted); task3.Start(); task4.Start(); Thread.Sleep(
    7000); Console.Read(); } private static int RunTask(string name,int seconds) { Console.WriteLine("Task {0} 运行在线程={1}中,是否在线程池 :{2}",name,
    Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(seconds));
    throw new Exception("测试错误信息!"); return 42 * seconds; } } }

    2.程序运行结果,如下图。

     

             当程序启动时,创建一个任务task1并尝试同步获取结果。Result属性的Get部分会使当前线程等待直到这个任务完成,并将异常传播给当前线程。在这种情况下,通过catch代码块可以很容易地捕捉异常,不过这个异常是封装异常。所以可以访问InnerException来获取异常信息。

             Task2使用GetAwaiter与GetResult来获取任务结果。这种情况下,不需要封装异常,TPL会提取异常。如果底层只有一个task,一次只提取一个异常。

    最后一个示例是两个任务(task3,task4)抛出异常的情况 。通过后续操作来处理异常,只有之前的任务完成之前有异常,这个后续操作才会被触发 。通过后续操作传递TaskContinuationOption.OnlyOrFaulted选项来实现 ,在抛出的异常中封装了两个异常。

  • 相关阅读:
    DB2中的prepare和bind
    MDC 设置CURRENTMDC ROLLOUT MODE
    TSO缩写
    docker资料仓库搭建
    mfs 使用心得
    个人简介
    C# 关于字符串中 符合正则表达式的指定字符的替换的方法
    学而不思则罔,思而不学则殆
    点击按钮下载效果
    菜鸟成长之路SQL Server事物学习,高手跳过
  • 原文地址:https://www.cnblogs.com/chillsrc/p/7993492.html
Copyright © 2011-2022 走看看