Task.WaitAll代替WaitHandle.WaitAll

Task.Waitall阻塞了当前线程直到全完。whenall开启个新监控线程去判读括号里的所有线程执行情况并立即返回,等都完成了就退出监控线程并返回监控数据。

task.Result会等待异步方法返回,当然阻塞住了。别和await 同时用。

Task和ThreadPool的功能类似,可以用来创建一些轻量级的并行任务。对于将一个任务放进线程池
    ThreadPool.QueueUserWorkItem(A);

这段代码用Task来实现的话,方式如下:
    Task.Factory.StartNew(A);

这两端代码的使用和实现的功能都十分相似。但和TheadPool相比,Task有着更多的功能,更加方便我们使用。

假如我们要创建三个任务,并等待它们完成。这个功能用TheadPool实现如下:

using (ManualResetEvent mre1 = new ManualResetEvent(false))
    using (ManualResetEvent mre2 = new ManualResetEvent(false))
    using (ManualResetEvent mre3 = new ManualResetEvent(false))
    {
        ThreadPool.QueueUserWorkItem(delegate
        {
            A();
            mre1.Set();
        });
        ThreadPool.QueueUserWorkItem(delegate
        {
            B();
            mre2.Set();
        });
        ThreadPool.QueueUserWorkItem(delegate
        {
            C();
            mre3.Set();
        });
        WaitHandle.WaitAll(new WaitHandle[] { mre1, mre2, mre3 });
    }

用Task类实现起来就相对简单多了:

Task t1 = Task.Factory.StartNew(delegate { A(); });
    Task t2 = Task.Factory.StartNew(delegate { B(); });
    Task t3 = Task.Factory.StartNew(delegate { C(); });
    t1.Wait();
    t2.Wait();
    t3.Wait();

或者我们还可以这么写:

Task t1 = Task.Factory.StartNew(delegate { A(); });
    Task t2 = Task.Factory.StartNew(delegate { B(); });
    Task t3 = Task.Factory.StartNew(delegate { C(); });
    Task.WaitAll(t1, t2, t3);

下面我们来简单的介绍一下Task的基本用法:

创建Task

创建Task有两种方式

  1. 通过构造函数创建
    Task t1 = new Task(A);
  2. 通过TaskFactory创建
    Task t1 = Task.Factory.StartNew(A);

这两种方式其实是一样的,第一种方式里面也传入了默认的TaskFactory——Task.Factory。TaskFactory起着对Task进行创建和调度管理的作用,类似于以前CTP版中的TaskManager,关于这个对象,后续会单独写一篇文章介绍。

开始运行Task

在上述两种创建Task方式中,方式1创建的Task并没有立即执行,需要手动调用t1.Start()来执行(类似于线程,需要手动执行)。而方式2创建的Task是立即执行的(类似于线程池,是自动执行的),从这两种方式的函数名称也可以看出这一点。

等待Task完成

等待Task完成的也有两种:

  1. 调用Task的成员函数t.Wait()。
  2. 调用Task的静态函数Task.WaitAll()或Task.WaitAny()。

这两种方式和.net中常用的WaitHandle差不多,这里就不多介绍了。

取消Task

取消Task的方式较CTP的时候复杂和强大了不少,后续加一个单独的篇章单独介绍。

异常处理

当Task在执行过程中发生异常时,该异常会在Wait或WaitAll等函数中重新throw。可以通过Task的Exception属性来获取发生的异常。

var t1 = Task.Factory.StartNew(() => { throw new Exception("t1 error occor"); });
    var t2 = Task.Factory.StartNew(() => { throw new Exception("t2 error occor"); });

try
    {
        Task.WaitAll(t1, t2);
    }
    catch (Exception)
    {
        Console.WriteLine(t1.Exception.InnerException.Message);
        Console.WriteLine(t2.Exception.InnerException.Message);
    }

获取Task的返回值

在CTP版本中,是通过Fucture<>类来获取带返回值的Task的,现在已经将类改名为Task<>了,从而实现命名方式的统一。使用方式几乎一致,就是多了一个Result属性,可以在Task执行完成后获取返回值。示例如下:

var t1 = Task.Factory.StartNew(() => 3);
    t1.Wait();
    Console.WriteLine(t1.Result);

时间: 2024-10-09 23:36:58

Task.WaitAll代替WaitHandle.WaitAll的相关文章

信号量 AutoResetEvent与WaitHandle.WaitAll使用。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication11 { class Program { static void Main(string[] args) { AutoResetEvent[] AutoR = ne

C# Task 用法

转自原文 C# Task 用法 C# Task 的用法 其实Task跟线程池ThreadPool的功能类似,不过写起来更为简单,直观.代码更简洁了,使用Task来进行操作.可以跟线程一样可以轻松的对执行的方法进行控制. 顺便提一下,配合CancellationTokenSource类更为可以轻松的对Task操作的代码进行中途终止运行,会在后面的章节中讲述. 如果我们使用线程池来实现某几个方法运行,然后等待运行完成的大概会编写如下代码: using (ManualResetEvent m1 = n

(译).NET4.X并行任务Task需要释放吗?

摘要:本博文解释在.NET 4.X中的Task使用完后为什么不应该调用Dispose().并且说明.NET4.5对.NET4.0的Task对象进行的部分改进:减轻Task对WaitHandle对象的依赖,并且增强在释放了Task后对其成员的可访问性. 我多次获得这样一个问题: “Task实现了IDisposable接口并且公开Dispose()方法,这是否意味着我们要对所有的任务进行释放吗?” 概述 这是我对该问题的简要回答: “不是,不用释放你持有的Task.” 这是我对该问题的中篇回答: “

C#的WaitHandle : 管理多线程状态

有时候,我们创建了多线程,需要知道是否都完成了各自的工作.比如说,开启了多线程的下载,如何终止所有的线程并且在确保所有线程都终止之后才继续执行程序的退出呢? 1 public partial class MainWindow : Window 2 { 3 public MainWindow() 4 { 5 InitializeComponent(); 6 } 7 8 private volatile bool isContinue = false; 9 static List<WaitHandl

关于Task的认识

首先来说说 Task.Factory.StartNew这种方式来创建Task,这里的WaitAll()指的是等待所有Task执行完成,并且里面的Task参数(t1,t2)是异步的,先以匿名委托方式 static void Main(string[] args) { Task t1 = Task.Factory.StartNew(delegate { MyMethodA(); }); Task t2 = Task.Factory.StartNew(delegate { MyMethodB(); }

C# 多线程处理相关说明: WaitHandle,waitCallback, ThreadPool.QueueUserWorkItem

class TestThread { static void Main() { //使用WaitHandle静态方法阻止一个线程,直到一个或多个同步对象接收到信号 WaitHandle[] waitHandles = new WaitHandle[] { new ManualResetEvent(false), new ManualResetEvent(false) }; WaitCallback waitCallback = new WaitCallback(MyThreadWork); Wa

C#多线程和异步——Task和async/await详解

阅读目录 一.什么是异步 二.Task介绍 1 Task创建和运行 2 Task的阻塞方法(Wait/WaitAll/WaitAny) 3 Task的延续操作(WhenAny/WhenAll/ContinueWith) 4 Task的任务取消(CancellationTokenSource) 三.异步方法(async/await) 回到顶部 一.什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时

Task和async/await详解

一.什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法. 异步的好处在于非阻塞(调用线程不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果.较耗时的任务设为异步执行,可以提高程序的运行效率.net4.0在ThreadPool的基础上推出了Task类,微软极力推荐使用Task来执行异步

多线程:线程同步之WaitHandle

一.引言 在前面的文章中,我们是使用“锁”的方式实现了线程间的通信,这种通信方式比较笨重.除了锁之外,.NET中还提供了一些线程间更自由通讯的工具,他们提供了通过“信号”进行通讯的机制,通俗的比喻为“开门”.“关门”:Set()开门.Reset()关门.WaitOne()等着. 二.WaitHandle WaitHandle位于System.Threading命名空间下,是用来封装等待对共享资源进行独占访问的操作系统特定的对象.WaitHandle是一个抽象类,我们一般不直接使用,而是使用它的派