C#线程安全使用(四)

这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来。

这里主要讲解下CancellationTokenSource,CancellationTokenSource是用于取消线程,具体使用起来有点另类:首先定义实体,然后将其下的属性ToKen传递给线程,当需要取消线程时,调用下Cancel()方法。例子我依然采用了MSDN的例子,但我做了一些修改,这个例子虽然看起来挺复杂,但还是记录了许多内容。

由于不好理解,我就粗略讲解下:

Task<double> fTask = factory.ContinueWhenAll(tasks.ToArray(), 上面是创建任务,创建10个线程,并且线程中增加了判断,如果随即数等于0就取消该线程。

 再介绍下factory.ContinueWhenAll,他包含两个参数Task[] tasks, Action<Task[]> continuationAction。MSDN的解释是:

ContinueWhenAll 方法执行 continuationAction 委托,在 tasks 数组的所有任务完成后,无论它们的完成状态。

MSDN上就这个翻译的还不错,其他的基本可以无视了。。。

继续看代码,代码中增加了try catch,这是为什么呢,看下ContinueWhenAll英文解释:

The exception that is thrown when the tasks array is empty

这里千万不能看中文解释,不然你会凌乱的。看了英文解释就懂了,让任务为空就抛异常。

那么为什么任务为空呢,因为任务已经被取消了啊,所以为空了。具体代码如下。

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
    public static void Main()
    {
        // Define the cancellation token.
        CancellationTokenSource source = new CancellationTokenSource();
        CancellationToken token = source.Token;
        Random rnd = new Random();
        Object lockObj = new Object();
        List<Task<int[]>> tasks = new List<Task<int[]>>();
        TaskFactory factory = new TaskFactory(token);
        for (int taskCtr = 0; taskCtr <= 10; taskCtr++)
        {
            int iteration = taskCtr + 1;
            tasks.Add(factory.StartNew(() =>
            {
                int value;
                int[] values = new int[10];
                for (int ctr = 1; ctr <= 10; ctr++)
                {
                    lock (lockObj)
                    {
                        value = rnd.Next(0, 101);
                    }
                    if (value == 0)
                    {
                        source.Cancel();
                        Console.WriteLine("Cancelling at task {0}", iteration);
                        break;
                    }
                   
                    values[ctr - 1] = value;
                }
                Console.WriteLine("NO Cancel at task {0}", iteration);
                return values;
            }, token));
        }
        try
        {
            Task<double> fTask = factory.ContinueWhenAll(tasks.ToArray(),
                                                         (results) =>
                                                         {
                                                             Console.WriteLine("Calculating overall mean...");
                                                             long sum = 0;
                                                             int n = 0;
                                                             foreach (var t in results)
                                                             {
                                                                 foreach (var r in t.Result)
                                                                 {
                                                                     sum += r;
                                                                     n++;
                                                                 }
                                                             }
                                                             return sum / (double)n;
                                                         }, token);
            Console.WriteLine("The mean is {0}.", fTask.Result);
        }
        catch (AggregateException ae)
        {
            foreach (Exception e in ae.InnerExceptions)
            {
                if (e is TaskCanceledException)
                    Console.WriteLine("Unable to compute mean: {0}",
                                      ((TaskCanceledException)e).Message);
                else
                    Console.WriteLine("Exception: " + e.GetType().Name);
            }
        }
        Console.ReadLine();
        
    }
}

显示结果图片,每次的结果都不一样的,所以我也是运行了好几次,看这个结果会发现一件事,线程只执行了两个,即当线程2中调用Cancel后,其他线程也被取消了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏二进制文集

Java 生产者消费者实现

chef 在 有 meal 的时候,会释放锁;在制作 meal 时,会获取 waitPerson 的锁,制作完 meal 后,唤醒所有的 waitPerson;

3614
来自专栏丑胖侠

《Drools7.0.0.Final规则引擎教程》番外实例篇——FactHandler使用案例

背景 在使用具体的业务使用中,我们经常会通代码对Fact对象进行操作,Drools为我们提供了FactHandler来获取对象的句柄,通过此返回值可以对Work...

2705
来自专栏跟着阿笨一起玩NET

Linq to XML 读取XML 备忘笔记

本文转载:http://www.cnblogs.com/infozero/archive/2010/07/13/1776383.html

970
来自专栏智能大石头

XCode新增数据转换功能(导数据)

用法: DAL.AddConnStr("xxgk", "Data Source=192.168.1.21;Initial Catalog=信息公开;user i...

2216
来自专栏技术博客

C#函数方法集

1、DateTime 数字型 System.DateTime currentTime=new System.DateTime();

1412
来自专栏草根专栏

使用两种方法让 ASP.NET Core 实现遵循 HATEOAS 结构的 RESTful API

HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 ...

58011
来自专栏GuZhenYin

[干货来袭]C#6.0新特性

微软昨天发布了新的VS 2015 ..随之而来的还有很多很多东西... .NET新版本 ASP.NET新版本...等等..太多..实在没消化.. 分享一下也是昨...

1988
来自专栏tkokof 的技术,小趣及杂念

Sweet Snippet 系列之 有序列表

很朴素的一种想法,为了维持 List 有序,我们可以在 Add 操作之后进行 Sort 操作(Remove 操作后不需要重新 Sort):

501
来自专栏Create Sun

mvc+webapi 单元测试 3.使用Moq模拟AspnetMvc中的Request.Form

 1.前言     现在这个项目已经有阶段性的模块完成了,所以就想着对这些模块进行单元测试,以保证项目的代码的质量。首先虽然标题是mvc+webapi实质上我只...

6309
来自专栏跟着阿笨一起玩NET

浅谈WebService开发(一)

       简单通俗来说,就是企业之间、网站之间通过Internet来访问并使用在线服务,一些数据,由于安全性问题,不能提供数据库给其他单位使用,这时候可以使...

3783

扫码关注云+社区

领取腾讯云代金券