任务表示某个工做单元。这个工做单元能够在单独的线程中运行,也能够同步方式启动一个任务,使主线程等待。任务能够在完成后定义一个连续工做,同时也能够有子任务(但取消父任务后,子任务也会被取消)。安全
使用TaskFactory类或Task类的构造方法和Start()方法。启动任务时,会建立一个Task类的实例,利用Action或者Action<object>委托,能够指定应该运行的代码。建立一个方法做为后面线程调用的代码:函数
static void TaskMethod(object title) { lock (taskMethodLock) { Console.WriteLine(title); Console.WriteLine("Task id: {0}, thread: {1}", Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(), Thread.CurrentThread.ManagedThreadId); Console.WriteLine("is pooled thread: {0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("is background thread: {0}", Thread.CurrentThread.IsBackground); Console.WriteLine(); } }
建立任务有四种方式: oop
static void TasksUsingThreadPool() { TaskFactory tf = new TaskFactory(); Task t1 = tf.StartNew(TaskMethod, "using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod, "factory via a task"); Task t3 = new Task(TaskMethod, "using a task constructor and Start"); t3.Start(); Task t4 = Task.Run(() => TaskMethod("using the Run method")); }
使用Task构造函数和TaskFactory的StartNew方法时,能够传递TaskCreationOptions的枚举值。它能够改变任务的行为。this
任务能够同步运行,以相同的线程做为主调线程。使用Task的RunSynchronously方法:spa
private static void RunSynchronousTask() { TaskMethod("just the main thread"); var t1 = new Task(TaskMethod, "run sync"); t1.RunSynchronously(); }
首先TaskMethod方法在主线程调用,而后在新建立的Task上调用。运行代码,从输出能够看出,主线程是一个前台线程。没有任务ID,也不是线程池的线程。调用RunSyncronously方法时,会使用相同的线程做为主调线程,可是若是之前没有建立任务,就会建立一个新任务。线程
若是任务须要长时间运行,那么使用TaskCreationOptions.LongRunning告诉任务调度器建立一个新的线程,而不是使用线程池中的线程。新线程将不受线程池管理。若是线程来自于线程池,任务调度器能够决定等待已经运行的任务完成,而后使用这个线程,而不是在线程中建立一个新的线程。对于长时间运行的线程,任务调度器会当即知道不能等待它们完成。调试
任务结束时,能够把一些有用的信息写入共享对象中,但共享对象必须是线程安全的。另外一种方法是使用返回某个结果的任务:code
static void ResultsFromTasks() { //TResult是后面Func的返回值,第二个参数是Func的传入参数 Task<Tuple<int, int>> t1 = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(8, 3)); t1.Start(); Console.WriteLine(t1.Result);//在此等待任务的完成,返回结果 //t1.Wait(); Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2); } static Tuple<int, int> TaskWithResult(object division) { Tuple<int, int> div = (Tuple<int, int>)division; int result = div.Item1 / div.Item2; int reminder = div.Item1 % div.Item2; Console.WriteLine("task creates a result..."); return Tuple.Create<int, int>(result, reminder); }
能够指定在任务完成后,应该开始运行的另外一个特定任务。如:一个任务失败后,那么任务的后续工做就是清理工做。任务处理程序不带参数,或者带一个object类型的参数,连续处理程序有一个Task类型的参数,能够访问起始任务的相关信息。对象
static void ContinuationTask() { Task t1 = new Task(DoOnFirst); //连续任务经过在任务上调用ContinueWith方法定义,也可使用TaskFactory类。 Task t2 = t1.ContinueWith(DoOnSecond);//调用DoOnSecond方法的新任务在任务t1结束后当即启动。 Task t3 = t1.ContinueWith(DoOnSecond);//在一个任务结束时,能够启动多个任务 Task t4 = t2.ContinueWith(DoOnSecond);//连续任务也能够另外一个连续任务 //不管前一个任务是如何结束的,前面的连续任务都会在前一个任务结束时启动 //使用TaskContinuationOptions的枚举值,能够指定连续任务启动的前提条件(前一个任务的状态) Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted); t1.Start(); Thread.Sleep(5000); } static void DoOnFirst() { Console.WriteLine("doing some task {0}", Task.CurrentId); Thread.Sleep(3000); } static void DoOnSecond(Task t) { Console.WriteLine("task {0} finished", t.Id); Console.WriteLine("this task id {0}", Task.CurrentId); Console.WriteLine("do some cleanup"); Thread.Sleep(3000); } static void DoOnError(Task t) { Console.WriteLine("task {0} had an error!", t.Id); Console.WriteLine("my id {0}", Task.CurrentId); Console.WriteLine("do some cleanup"); }
利用任务的连续性,能够在一个任务结束后启动另外一个任务。任务也能够构成一个层次结构,一个任务启动一个新任务时,就启动了一个父/子层次结构。blog
static void ParentAndChild() { Task parent = new Task(ParentTask); parent.Start(); Thread.Sleep(2000); Console.WriteLine(parent.Status); Thread.Sleep(4000); Console.WriteLine(parent.Status); } static void ParentTask() { Console.WriteLine("task id {0}", Task.CurrentId); var child = new Task(ChildTask); child.Start(); Thread.Sleep(1000); Console.WriteLine("parent started child"); } static void ChildTask() { Console.WriteLine("child"); Thread.Sleep(5000); Console.WriteLine("child finished"); }
父任务在子任务以前结束,则父任务状态为WaitingForChildrenToComplete;全部的子任务也结束时,父任务的状态为RanToCompletion。取消父任务,也会取消子任务。
//:启动父/子关系结构任务的另外一种方法 static void ParentAndChild() { TaskFactory factory = new TaskFactory(); Task parent = factory.StartNew(() => { Console.WriteLine("parent task {0}", Task.CurrentId); Task child = factory.StartNew(() => { Console.WriteLine("child task {0}", Task.CurrentId); Thread.Sleep(2000); Console.WriteLine("finished child"); }, TaskCreationOptions.AttachedToParent); Console.WriteLine("finished parent"); }); parent.Wait(); }
static void CancelTask() { var cts = new CancellationTokenSource();//也可使用Task.Factory.CancellationToken(若是仅须要一个取消标记) cts.Token.Register(() => Console.WriteLine("*** task cancelled"));//在发生取消标记时调用。 cts.CancelAfter(500); //500ms后取消任务 Task t1 = Task.Run(() => { Console.WriteLine("in task"); for (int i = 0; i < 20; i++) { Thread.Sleep(100); CancellationToken token = cts.Token; if (token.IsCancellationRequested) { Console.WriteLine("cancelling was requested, cancelling from within the task"); token.ThrowIfCancellationRequested();//注意:运行调试程序会在此处报异常,运行exe会在下面捕捉到异常 break; } Console.WriteLine("in loop"); } Console.WriteLine("task finished without cancellation"); }, cts.Token); try { t1.Wait(); } catch (AggregateException ex) { Console.WriteLine("exception: {0}, {1}", ex.GetType().Name, ex.Message); foreach (var innerException in ex.InnerExceptions) { Console.WriteLine("inner excepion: {0}, {1}", ex.InnerException.GetType().Name, ex.InnerException.Message); } } }