线程----计算限制的异步操作2

vsvim------------参考1,,参考2





1,基本的线程操作:

Thread t1= new Thread(ThreadCallBack)
t1.start(object)
...
t1.join();//线程阻塞

t1.abort()//线程终止

t1.IsBackGround//是否前台线程.

2线程池

线程池是一个由CLR管理的集合.线程池内部维护一个操作请求队列.当应用程序有异步操作请求的时候,则将一个记录项添加到线程池队列中.

线程池的代码在这里提取记录想.将其派发给一个线程池线程.如果没有线程,就创建一个.


当一定时间线程池的线程没有动作.其会主动苏醒并且自我销毁.


3,将一个线程添加到线程池



ThreadPool.UserWorkItem(WaitCallBack,object state)//添加方法到线程池里面去.


4,执行上下文.

  每个线程都关联了一个执行上下文

                    有CallContext.LogicalSetData和LogicalGetData.

 CallContext.LogicalSetData("Name", "Jeffry");
            ThreadPool.QueueUserWorkItem(state =>
            Console.WriteLine("{0}", CallContext.LogicalGetData("Name")));
            ExecutionContext.SuppressFlow();
            ThreadPool.QueueUserWorkItem(state =>
            Console.WriteLine("{0}", CallContext.LogicalGetData("Name")));
            ExecutionContext.RestoreFlow();
            Console.ReadLine();

5,协作式取消

 public static void test2()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));
            Console.ReadLine();
            cts.Cancel();
            Console.ReadLine();
        }

        private static void Count(CancellationToken token, int v)
        {
            for(var i = 0; i < v; i++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("canceled");
                    break;
                }
                Console.WriteLine(i);
                Thread.Sleep(200);
            }
        }

   1,CancellationToken 有一个值类型 None.对于这个类型,Cancanceled 是false,其他由 CancellationTokenSource产生的是true.

   2,可以使用Register方法来注册当线程取消的时候的回调函数.要向方法传递一个 Action<object>委托. 和一个指明Synchronizaton

Context的标志,传递 false,则 cancell()所在的线程会顺序执行所有回调的方法.

       传递true,则回调方法将send给已捕捉的SynchronizationContext对象.后者决定哪个线程调用回调方法.

   3, 向Cancel()方法传递 false,则抛出异常的回调方法会阻止其他回调方法.并且cancell也将抛出该异常.

   当设定true的时候,cancel(true)将执行所有回调函数.并且抛出一个AggregateException.所有异常在AggregateException.Inner之中.

   4,register方法返回一个CancellationToken对象.可以使用Dispose()方法,注销掉注册的方法.

   5,最后,可以使用链接另一个CancellationTokenSource对象来创建一个 CancellationTokenSource 对象.

任何一个链接的CancellationTokenSource对象被取消.则,本对象液会被取消.

  public static void test3()
        {
            CancellationTokenSource cts1 = new CancellationTokenSource();
            CancellationTokenSource cts2 = new CancellationTokenSource();
            CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);
            cts1.Cancel();
            Console.WriteLine("{0},{1},{2}", cts1.Token.IsCancellationRequested, cts2.Token.IsCancellationRequested, linked.Token.IsCancellationRequested);
            Console.ReadLine();

        }

6,使用CancelAfter和构造函数的定时功能,定时取消.



7,等待任务完成并获取结果----------使用Task方式

        1,new Task(....).start

        2,Task.Run()

       3,ThreadPool.QueueUserWorkItem

   当一个任务被执行的时候,如果其抛出了 未处理的异常,那么异常会被吞噬,并存储到一个集合当中.

  当调用,wait 或者 Result 属性的时候,这些成员会抛出一个 AggregateException对象.

     该对象的 InnerExceptions属性返回一个 ReadOnlyCollection<Exception>对象.

     其重写了GetBaseException()对象,返回作位内层根源的 AggregateException对象.

      其还提供了一个 一个Flatten方法,其创建一个新的AggregateException对象.其异常通过遍历元素的AggregateException的内层异常结构层次而生.

      最后,还提供了一个handle方法,会为每个异常调用一个回调方法.回调返回true表示异常已经处理. 如果 还有异常没有处理,就抛出新的AggregateException异常.

  public static void test4()
        {
            Task t = Task.Run(() =>
            {
                Task t1 = Task.Run(() => { Thread.Sleep(1000); throw new Exception("t1 error"); });
                Task t2 = Task.Run(() => { Thread.Sleep(1000); throw new Exception("t2 error"); });
                Task t3 = Task.Run(() => { Thread.Sleep(3000); throw new Exception("t3 error"); });
                Task t4 = Task.Run(() => { Thread.Sleep(3000); throw new Exception("t4 error"); });
                Task.WaitAll(t1, t2, t3, t4);
            }

            );
            try
            {
                t.Wait();
            }
            catch(AggregateException e)
            {
                var t1 = e;
                DispalyAggregateException(0, e);

            }
            Console.ReadLine();
        }

        public static void DispalyAggregateException(int indent,AggregateException e)
        {

            string indents = string.Format(" ", indent * 3);

            Console.WriteLine(indents + "AggregateException has {0} inners", e.InnerExceptions.Count);
            for(var i = 0; i < e.InnerExceptions.Count; i++)
            {
                var ie = e.InnerExceptions[i];
                if (ie is AggregateException) DispalyAggregateException(indent + 1, (AggregateException)ie);
                else
                    Console.WriteLine(indents+" Exception type {0} Exception Message {1}", ie.GetType(), ie.Message);
            }


        }

进行分析一波  首先:

主线程是  Test4(),其下有一个分线程 t,

                             所以,我们在 使用 t.wait()这个函数的时候, 将会捕捉 分任务t 中抛出的未经处理异常 AggregateException

            分线程t下面有4个小分线程:

                              t1,t2,t3,t4.

          对于线程t来说.他在 Task.WaitAll(t1,t2,t3,t4)指令等待所有线程运行完毕,并且捕捉每个线程的异常.其只会抛出一个异常.

                对于t1,t2… 而言,其内部没有分线程,只有同步的执行方法. 并且抛出了异常.

AggregateException has 1 inners
   AggregateException has 4 inners
    Exception type System.Exception Exception Message t1 error
    Exception type System.Exception Exception Message t2 error
    Exception type System.Exception Exception Message t3 error
    Exception type System.Exception Exception Message t4 error

可以看到层次结构. 

          4, Async Task xxxx和 Async void 的区别

                        Async void 由于不返回任务,所以无法等待,也就是无法获取异常和结果.

                        Async Task返回一个任务,可以获取结果.

  public static async Task OpenPlcTest(CancellationToken token)//设置void 则 表明当执行到await 以后,wait函数就任务返回了.否则,Task,则要等到整个流程执行完毕再返回.
        {
            Plc plc = new Plc(CpuType.S71200, "192.168.0.13", 0, 1);


            Task t1 = Task.Run(async () =>

             {
                 Task p1 = plc.OpenAsync();

                 while (!p1.IsCompleted) token.ThrowIfCancellationRequested();//这个函数用于接收取消任务.
                 await p1;
             }


          , token);

            try
            {
                await t1;
            }
            catch (Exception e)
            {
                DispalyAggregateException(0, e);
                throw e;
            }
            finally
            {
                if (!plc.IsConnected)
                    plc.Close();
            }






        }
        public static void Test5()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            Task t = Task.Run(() => OpenPlcTest(cts.Token));

            try
            {
                Task.Run(() =>
                {
                    Console.ReadLine();
                    cts.Cancel();
                });
                t.Wait();
                Console.WriteLine("Completed the job");
            }
            catch (AggregateException e)
            {
                DispalyAggregateException(0, e);
            }


        }
    }


8,继续新的任务:

   使用任务的Continuewith() 进行新的任务.

 public static void Test6()
        {

            CancellationTokenSource cts = new CancellationTokenSource();

            Task t = Task.Run(() =>
            {
                for (var i = 0; i < 30; i++)
                {
                    if (cts.Token.IsCancellationRequested) cts.Token.ThrowIfCancellationRequested();
                    Console.WriteLine(i.ToString());
                    Thread.Sleep(1000);
                }
                Console.WriteLine("task competed");
            },cts.Token);
            Task.Run(() =>
                            {
                                Thread.Sleep(4000);
                                cts.Cancel();
                            });
            t.ContinueWith(task =>
            {
                Console.WriteLine(t.Status);
                Console.WriteLine(t.IsCanceled);
            });






        }

只有使用Throw的方式终止的才是IsCanceled错误,其他是IsFauted.

-------匿名异步lambda表达式的返回值

 Task t = new Task<Task<int>>(async () =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("222222");
                await Task.Run(() =>
                {
                    Thread.Sleep(5000);
                    Console.WriteLine("111111111");
                }
                    );
                return 16;
            });
            t.Start();
            t.Wait();

注意,异步的lambda表达式如果返回值,总是返回一个Task.

当使用Task 时 非Task<xx>形式时,忽略返回的Task.Result.

posted @ 2020-03-01 16:18  frogkiller  阅读(143)  评论(0编辑  收藏  举报