原文地址:http://www.cnblogs.com/yinzixin/archive/2011/11/04/2235233.html

.NET 4为了简化多线程编程,提供了System.Threading.Tasks命名空间中的类来帮助开发者进行多线程编程,其中,Task类用来表示一个线程。最简单的Task类接受一个Action委托作为要执行的方法,调用Start方法开始在另一个线程中运行。例如:

using System;
using System.Threading.Tasks;
namespace TaskParallel
{
class Program
{
static void Main(string[] args)
{
Task task=new Task(()=> Console.WriteLine("Write from another thread"));
task.Start();
Console.WriteLine("Main Thread");
Console.ReadLine();
}
}
} 两句输出的顺序是不一定的,但是很有可能是:

Main Thread 
Write from another thread

也可以使用Task.Factory.StartNew方法,这个方法会构造一个Task并且立刻开始运行,相当于将Task的构造函数和Start方法连在一起执行。

Task类还有一个构造函数可以接受Action<object>委托,用来向Action委托传递参数:

static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Task t = new Task(obj => Console.WriteLine("Thread No " + obj), i);
t.Start();
}
Console.ReadLine();
}

输出的结果类似于:

Thread No 2 
Thread No 1 
Thread No 3 
Thread No 0 
Thread No 4

可以使用Task<T>类来获得返回值,T是返回值的类型,例如:

static void Main(string[] args)
{
Task<int> t = new Task<int>(() =>
{
int s=0;
for (int i = 0; i < 10000; i++)
s += i;
return s;
});
t.Start();
Console.WriteLine("I'm computing");
Console.WriteLine(t.Result);
Console.ReadLine();
}
结果为:

I'm computing 
49995000

在访问t.Result的时候,.net 会保证此时Task的代码已经执行完毕,Result已经获得,否则该线程会阻塞,直到Result计算完毕。

Task库提供了一种主动终止线程的方法,先创建一个CancellationTokenSource,将其Token属性通过Task构造函数传进去,在Task内部轮询token的IsCancellationReqeusted属性,如果检测到为true,则主动终止线程。在父线程内调用tokenSource的Cancel方法,可以终止线程。注意,这是线程主动终止自己的方法,必须在Task内的代码自己终止,.NET不会强行终止task线程,即使父线程调用了tokenSource的Cancel方法。

例如下面的代码,如果在else语句块内没有break语句,子线程是不会终止的。

using System;
using System.Threading;
using System.Threading.Tasks; namespace TaskParallel
{
class Program
{
static void Main(string[] args)
{
CancellationTokenSource tks = new CancellationTokenSource();
CancellationToken token = tks.Token;
long i = 0;
Task task = new Task(() =>
{
while (true)
{
if (!token.IsCancellationRequested)
i++;
else
{
Console.WriteLine("Task is canceled, it looped "+i+" times");
break;
}
}
},token);
task.Start();
Console.WriteLine("Press Enter to Cancel task");
Console.ReadLine();
tks.Cancel();
Console.ReadLine();
}
}
}

还可以通过CancellationToken的Register方法给token注册一个委托,当调用tokenSource的Cancel方法的时候,这个委托会被执行。这个委托是在调用Cancel方法的线程中执行的。

token.Register(() => { Console.WriteLine("Delegate Invoked"); });
 
要挂起当前线程,等待一个线程执行完成,可以使用执行线程的Wait()方法,Wait方法有一些重载方法,可以指定等待的时间等,例如:
static void Main(string[] args)
{
Task t1 = new Task(() =>
{
Console.WriteLine("Task 1 Starts...");
Thread.Sleep(3000);
Console.WriteLine("Task1 Ends");
});
t1.Start();
Task t2 = new Task(() =>
{
Console.WriteLine("Task2 Starts...");
t1.Wait();
Console.WriteLine("Task2 Ends");
});
Task t3 = new Task(() =>
{
Console.WriteLine("Task 3 is waiting Task1 for 1 second...");
bool finished=t1.Wait(1000);
if (finished)
Console.WriteLine("T1 is finished");
else
Console.WriteLine("T1 is not finished");
});
t2.Start();
t3.Start();
Console.ReadLine();
}

执行结果为:

Task 1 Starts... 
Task2 Starts... 
Task 3 is waiting Task1 for 1 second... 
T1 is not finished 
Task1 Ends 
Task2 Ends

要等到多个线程都执行完可以使用Task.WaitAll方法,

Task t4 = new Task(() =>
{
Console.WriteLine("Waiting for all");
Task.WaitAll(t1, t2, t3);
Console.WriteLine("Task4 Ends");
});
t4.Start();

还有一个Task.WaitAny,可以等待一组线程中的任何一个方法执行完毕,用法类似。

下面介绍Task中的异常处理,通常情况下,线程委托中的异常会导致线程终止,但异常并不会被抛出,例如:

Task t = new Task(() =>
{
throw new Exception();
Console.WriteLine("Thread Ends");
});
t.Start();
Console.WriteLine("Main Ends");

输出的是:

Main Ends

当调用Wait,WaitAll,WaitAny,Task.Result的时候,会抛出AggerateException ,在AggerateExcepiton中可以处理所有线程抛出的异常:

static void Main(string[] args)
{
Task t1 = new Task(() =>
{
throw new Exception();
Console.WriteLine("T1 Ends");
}); Task t2 = new Task(() =>
{
throw new ArgumentException();
Console.WriteLine("T2 Ends");
});
t1.Start();
t2.Start();
try
{
Task.WaitAll(t1, t2);
}
catch (AggregateException ex)
{
foreach (var inner in ex.InnerExceptions)
{
Console.WriteLine(inner.GetType() + " " + inner.Source);
}
}
Console.WriteLine("Main Ends");
}
}

有时候需要区分对待某些异常,一些异常直接处理掉,一些异常需要再次抛出,AggregateException提供一个Handle方法,接收一个Func<Exception,bool>委托作为参数,如果不需要再次抛出则返回true,否则返回false。

try
{
Task.WaitAll(t1, t2);
}
catch (AggregateException ex)
{
foreach (var inner in ex.InnerExceptions)
{
Console.WriteLine(inner.GetType() + " " + inner.Source);
}
ex.Handle((e) =>
{
if (e is ArgumentException)
{
Console.WriteLine("Argument Exception is captured");
return true;
}
else
return false;
});
}
这样就会有未处理的异常被抛出,抛出的仍然是AggregateException.

.NET 4中的多线程编程之一:使用Task(转载)的更多相关文章

  1. JavaEE开发之Spring中的多线程编程以及任务定时器详解

    上篇博客我们详细的聊了Spring中的事件的发送和监听,也就是常说的广播或者通知一类的东西,详情请移步于<JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换&g ...

  2. Java中的 多线程编程

    Java 中的多线程编程 一.多线程的优缺点 多线程的优点: 1)资源利用率更好2)程序设计在某些情况下更简单3)程序响应更快 多线程的代价: 1)设计更复杂虽然有一些多线程应用程序比单线程的应用程序 ...

  3. Python中的多线程编程,线程安全与锁(二)

    在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...

  4. Qt中的多线程编程

    http://www.ibm.com/developerworks/cn/linux/l-qt-mthrd/ Qt 作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功 ...

  5. C语言中的多线程编程

    很久很久以前,我对C语言的了解并不是很多,我最早听说多线程编程是用Java,其实C语言也有多线程编程,而且更为简单.方便.强大.下面就让我们简单领略一下Unix C语言环境下的多线程编程吧! 下面先看 ...

  6. 每天进步一点点——论fork()函数与Linux中的多线程编程

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/27316803 一.fork()函数     在操作系统的基本概念中进程是程序的一次运行,且是 ...

  7. Python中的多线程编程,线程安全与锁(一)

    1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...

  8. Android中的多线程编程(一)附源代码

    Android中多线程编程:Handler类.Runnable类.Thread类之概念分析 1.Handler类: Handler是谷歌封装的一种机制:能够用来更新UI以及消息的发送和处理.Handl ...

  9. python中的多线程编程与暂停、播放音频的结合

    先给两个原文链接: https://blog.csdn.net/u013755307/article/details/19913655 https://www.cnblogs.com/scolia/p ...

随机推荐

  1. 大型运输行业实战_day06_1_购票功能简单实现

    1.添加购票按钮 对应的html代码 因为列表是js函数动态填充的,故添加按钮应该在js函数中,完整代码如下: /** * 注意在调用该函数时必须输入参数 * 查询+ 分页 * */ function ...

  2. Cause: org.xml.sax.SAXParseException; lineNumber: 45; columnNumber: 62; 元素内容必须由格式正确的字符数据或标记组成。

    三月 09, 2018 12:13:39 下午 org.apache.catalina.core.StandardContext listenerStart严重: Exception sending ...

  3. python简单基础代码

    1.从键盘输入两个数,并计算A的B次幂:number1=raw_input('input number1:')number2=raw_input('input number2:')print 'num ...

  4. Codeforces Round #534 (Div. 2)

    B. Game with string 题意: 给出一个字符串s只包括小写字母.当轮到一个玩家的时候,他可以选择两个连续且相等的字母并且删除它.当一个玩家没得删的时候他就输了. 题解: 乍一看有点懵, ...

  5. phpStudy5——php导入其他php文件(php文件的引入)

    前言: 通过前边几个例子,相信大家都会有一个疑惑了,就是每个请求数据库的php页面,都要写一次连接数据库的代码,这个肯定是有违代码复用原则的.那么怎么解决这个问题呢? 在php中可以通过include ...

  6. leetcdoe 175. Combine Two Tables

    给定两个表,一个是人,一个是地址,要求查询所有人,可以没有地址. select a.FirstName, a.LastName, b.City, b.State from Person as a le ...

  7. centos7.5配置双网卡上网

    一.环境及说明 当初有这个需求,主要是帮一个高校的客户搭建一个大数据集群,使用的是校园网,交换机上一个端口只能连接一部电脑上网,不能通过路由组建子网,确保集群中的服务器有子网ip的同时,也能够通过公网 ...

  8. js和jquery获取span里面的值

    JQ和Js获取span标签的内容 html: 1 <span id="content">‘我是span标签的内容’</span> javascript获取: ...

  9. java Arrays.asList用法

    java Arrays.asList用法 用途 Arrays是java容器相关操作的工具类,asList方法将Array转换为list,是Array和List之间的桥梁. 注意 Arrays.asLi ...

  10. 02 Maven 入门使用

    Maven 入门使用 1. Maven 项目工程目录约定 Project |-src | |-main | | |-java -- 存放项目的 .java 文件 | | |-resources -- ...