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是异步的是不会阻塞线程的。