Fork me on GitHub

Task CancellationTokenSource和Task.WhenAll的应用

Task是.net4.0推出的异步编程类,与ThreadPool.QueneUserWorkItem方法类似的是,Task也是使用线程池来工作的.但Task比起这个QueneUserWorkItem的优势是它的可控制性,能够通过CancellationTokenSource控制Task运行任务的取消,还能够知道Task运行任务是何时完成的.Task对线程的阻塞控制有静态方法WaitAll(params Task[] tasks)我的理解是,当所有的tasks都完成得时候线程就不会阻塞,WaitAny(params Task[] tasks))表示只要tasks中其中任意一个任务完成,线程就不会再是阻塞状态.,成员方法Wait方法有四个重载,它们分别是:

  • public void Wait()
  • public bool Wait(TimeSpan timeout)
  • public void Wait(CancellationToken cancellationToken)
  • public bool Wait(int millisecondsTimeout)
  • public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)

对于Task的介绍就到这里,下面来看看它的一个例子,这个例子,我要做的就是:当点击按钮时,用两个任务t2,t3来sleep5秒钟,同时用任务t1在uI界面死循环的更新listbox读秒时间,当t2,t3任务结束了,在利用Task.WenAll和CancellationTokenSource break掉t1的死循环。效果如图所示:

代码如下:

CancellationTokenSource cts = new CancellationTokenSource();

        private void button1_Click(object sender, EventArgs e)
        {

            Task t2 = new Task(() =>
            {
                Thread.Sleep(5000);
            });
            //為了说明Task的异步,t2 和 t3都sleep5秒,但程序只数了5秒就结束了,这间接说明t2和t3是异步的
            Task t3 = new Task(() =>
            {
                Thread.Sleep(5000);
            });
            //死循环读秒
            Task t1 = new Task((obj) =>
            {

                object[] objs = obj as object[];

                CancellationTokenSource cancellationToken = objs[0] as CancellationTokenSource;//这个控制任务取消的

                string strParam = objs[1].ToString();

                int i = 1;
                while (true)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    if (listBox1.InvokeRequired)
                    {

                        listBox1.Invoke(new Action(() =>
                        {
                            listBox1.Items.Add(strParam + ":" + i++);

                        }));
                    }
                    else
                    {
                        listBox1.Items.Add(strParam + ":" + i++);
                    }

                    Delay(1000);

                }
            }, new object[2] { cts, "params" }, cts.Token);//这里随便写了一个参数,当任务需要参数的时候就“{ cts, "params" }“这样传,并且把控制任务取消的令牌cts.Token传进去
if (button1.Text == "start") 
{ button1.Text
= "sleep...";
t1.Start(); t2.Start();
t3.Start();
Task task
= Task.WhenAll(t2, t3);//这个WhenAll不会像WaitAll那样阻塞线程,所以会在t2和t3都sleep的情况下执行t1那个死循环线程
          //这里在建一个死循环任务去判断task是否完成 Task.Run(()
=> { while (true) { if (task.IsCompleted)//当t2和t3都完成得时候,这里就为true { cts.Cancel();//这里是对Task的取消操作,当执行了这句话时,这里cancellationToken.IsCancellationRequested就变成true
MessageBox.Show("結束!"); break; } } }); } }

大概就是这样,Task.WenAll是异步的是不会阻塞线程的。

posted @ 2019-01-18 14:31  HelloLLLLL  阅读(668)  评论(0编辑  收藏  举报