C#多线程之 任务工厂

    有时候 需创建一组具有相同状态的Task对象, 可使用System.Threading.Tasks命名空间中TaskFactory<TResult>类型和TaskFactory类型,两者均派生自System.Object。所有任务可共享的属性有:CancellationToken,TaskScheduler, TaskCreationgOption, TaskContinuation.


对此有以下测试目的:

1. 任务工厂内各任务是否异步执行

2. CancellationTokeSource类对协作式的影响

3. 父子任务的影响关系

4. 任务错误信息的捕获

5. ContinueWith 与 ContinueWhenAll的使用


using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.Threading.Tasks;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Task parent = new Task(() =>
            {
                var cts = new CancellationTokenSource();
                var tf = new TaskFactory(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                var childrenTasks = new[]
                {
                    tf.StartNew(() => sum(cts.Token,500)),
                    tf.StartNew(() => sum(cts.Token, 100)),
                    tf.StartNew(() => sum(cts.Token, 1000)),
                    tf.StartNew(() => sum(cts.Token, 200)),
                    tf.StartNew(() => sum(cts.Token, 3000)),
                    tf.StartNew(() => sum(cts.Token, 400)),
                    tf.StartNew(() => sum(cts.Token, 800)),
                   
                };


                for (int task = 0; task < childrenTasks.Length; task++)
                    childrenTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);

                tf.ContinueWhenAll(childrenTasks,
                    completedTasks => completedTasks.Where(
                        t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result), CancellationToken.None).ContinueWith(
                        t => Console.WriteLine("The max is: " + t.Result),
                            TaskContinuationOptions.ExecuteSynchronously);
            });

            parent.ContinueWith(p =>
            {
                StringBuilder sb = new StringBuilder("The following exception(s) occurred: " + Environment.NewLine);

                if (p.Exception != null)
                {
                    foreach (var e in p.Exception.Flatten().InnerExceptions)
                        sb.AppendLine(" " + e.GetType().ToString());
                }

                Console.WriteLine(sb.ToString());
            }, TaskContinuationOptions.OnlyOnFaulted);


            parent.Start();

            Console.ReadKey();
        }

        private static int sum(CancellationToken token, int n)
        {
            int sum = 0;

            int tmp = n;

            Console.WriteLine();
            Console.WriteLine(n);

            Thread.Sleep(1000);
          
                for (; n > 0; n--)
                {
                    if (token.IsCancellationRequested)
                    {
                        Console.WriteLine("\nCount is cancelled");
                        break;
                    }

                    checked { sum += n; }
                    Console.Write(" n" + n.ToString());
                }

                Console.WriteLine("\n" + tmp.ToString() + "End!");
            return sum;
        }


分析:

1. 代码分为两部分 第二部分用于计算求和,且随时根据token值决定是否结束当前任务;第一部分创建父子线程

2. 父线程parent下利用TaskFactory创建若干同属性线程,均采用默认任务调度方式

3. for循环通知所有线程,如果一个线程faulted其余线程均停止工作。

childrenTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);

本身便是个任务,只是这个任务只有满足条件TaskContinuationOptions.OnlyOnFaulted才会执行Action:cts.Cancel()

4. 当childrenTasks所有任务完成后,取出没故障的(!t.IsFaulted)并不被取消的(!t.IsCanceled)的所有任务的最大值,并打印到屏幕上来。 注意之所以调用CancellationToken.None是因为tf.ContinueWhenAll仍属于parent的子任务,会受到cts.Token影响,所以通过覆盖CancellationToken.None以达到一直显示的目的。

5 parent在所有子任务的sum计算完成后(而不等待tf.ContinueWhenAll(...)执行完成)显示错误信息。


可得到以下结论:

1. 如下图: 任务工厂内各个任务异步执行;parent.ContinueWith与tf.ContinueWhenAll无直接关系。


2. 更改代码为

                var childrenTasks = new[]
                {
                    tf.StartNew(() => sum(cts.Token,500)),
                    tf.StartNew(() => sum(cts.Token, 100)),
                    tf.StartNew(() => sum(cts.Token, Int32.MaxValue)),
                    tf.StartNew(() => sum(cts.Token, 200)),
                    tf.StartNew(() => sum(cts.Token, 3000)),
                    tf.StartNew(() => sum(cts.Token, 400)),
                    tf.StartNew(() => sum(cts.Token, 800)),
                   
                };
可得到


从而看出,当某一任务故障后导致cts.Cancel()执行;因此有两个任务(计数为200和3000)被终结.

3.推测:(不知是否正确)

父任务的结束标志是所有子任务完成,但不包括子任务所启动的任务。





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值