为什么要将取消令牌传递给TaskFactory.StartNew?

Zé *_*los 10 c# task-parallel-library

除了最常见的调用TaskFactory.StartNew的形式,只有"action"参数(1)https://msdn.microsoft.com/en-us/library/dd321439 ( v= vs.110).aspx

我们还有一种方法可以接受额外的参数作为"取消令牌"(2)https://msdn.microsoft.com/en-us/library/dd988458.aspx

我的问题是,我们为什么要使用call(2)而不是call(1)?

我的意思是,如果我没有将取消令牌作为参数传递(因为可以从委托函数访问变量令牌),页面(2)的MSDN中的示例也可以工作.例如:

var tokenSource = new CancellationTokenSource();
      var token = tokenSource.Token;
      var files = new List<Tuple<string, string, long, DateTime>>();

      var t = Task.Factory.StartNew( () => { string dir = "C:\\Windows\\System32\\";
                                object obj = new Object();
                                if (Directory.Exists(dir)) {
                                   Parallel.ForEach(Directory.GetFiles(dir),
                                   f => {
                                           if (token.IsCancellationRequested)
                                              token.ThrowIfCancellationRequested();
                                           var fi = new FileInfo(f);
                                           lock(obj) {
                                              files.Add(Tuple.Create(fi.Name, fi.DirectoryName, fi.Length, fi.LastWriteTimeUtc));          
                                           }
                                      });
                                 }
                              }
                        ); //note that I removed the ", token" from here
      tokenSource.Cancel();
Run Code Online (Sandbox Code Playgroud)

当我将取消令牌传递给Task.Factory.StartNew时,下面是否发生了什么?

谢谢

Sco*_*ain 10

会发生两件事.

  1. 如果在调用StartNew之前取消了令牌,它将永远不会启动该线程,并且该任务将处于该Canceled状态.
  2. 如果OperationCanceledException从任务内部引发a 并且该异常以相同的标记传递,StartNew则会导致返回的Task进入该Cancelled状态.如果与异常关联的令牌是不同的令牌,或者您未在任务中传递令牌,则将进入该Faulted状态.

PS你不应该Task.Factory.StartNew在没有传入的情况下调用,TaskScheduler因为如果你不这样做,它很容易导致你在你希望在后台线程上运行的UI线程上运行代码.使用Task.Run(替代,除非你absoultely需要使用StartNew,Task.Run具有相同的CancellationToken行为StartNew.