什么时候内联任务?

时间:2011-12-06 19:50:34

标签: c# .net multithreading task-parallel-library task

here等来源读取TPL中的内联后,我得到的印象是对Task.Wait()的调用将启动尚未开始的任务(至少使用默认调度程序) )。但是,写一个快速演示,如:

var taskB = new Task(
  () =>
      {
        Console.WriteLine("In TaskB");
        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("Leaving TaskB");
      });

var taskA = new Task(
  () =>
      {
        Console.WriteLine("In TaskA");
        System.Threading.Thread.Sleep(500);
        Console.WriteLine("Waiting on TaskB");
        taskB.Wait();
        Console.WriteLine("Leaving TaskA");
        });

taskA.Start();
taskA.Wait();

导致死锁。 TaskA进入taskB.Wait()行,但taskB永远不会启动。我没有搞乱调度程序或任何东西,所以我不确定为什么对taskB的.Wait()调用不会导致它启动。

2 个答案:

答案 0 :(得分:15)

Wait()不会导致任务Start()。如果在未启动的任务上调用Wait(),它将等待它开始并完成,直到完成,等待超时或等待被取消。由于您对Wait()的调用不包含取消令牌或超时,因此完成任务无限。

我认为你在博客中有什么令人困惑的是这一行:

  

但是,如果它还没有开始执行,Wait可能会拉动   将任务排除在排队并执行的调度程序之外   它内联在当前线程上。

这里的关键是“尚未开始执行”。这并不意味着Start()未被调用,而是Start() 调用,它调度任务并使其准备好执行,但任务尚未开始执行。

Start()是安排执行任务所必需的,它不会立即开始执行。这是那个模糊的主要观点。如果任务已准备好但尚未安排,则可以内联。但它不会启动甚至没有安排的任务。

如果您查看MSDN(See here)中的TaskStatus,您会看到以下值:

  • 已创建
  • WaitingForActivation
  • WaitingToRun
  • 运行
  • WaitingForChildrenToComplete
  • RanToCompletion
  • 已取消
  • 断陷

创建任务(使用new或factory)时,它处于Created状态。在这种状态下任务没有任何变化。一旦它开始,然后它移动到WaitingForActivation,依此类推,直到它到达Running,根据该博客可以内联它是可能的。

所以,长话短说,创建任务只是将其置于Created状态,如果调用Wait()则不会启动它。有意义吗?

答案 1 :(得分:2)

该文章中提到的内联与任务开始不同。等待任务不会启动它 - 这可以很容易地证明。试试以下内容:

namespace Test
{
    using System;
    using System.Threading.Tasks;

    internal class TestCompile
    {
        private static void Main(string[] args)
        {
            Task t = new Task(() => Console.WriteLine("Executed!"));
            t.Wait(5000);
            Console.WriteLine("After wait...");
            Console.ReadKey();
        }
    }
}

你会发现任务永远不会开始......

task.Wait()的调用无法启动任务。如果出现以下情况,它将导致Task立即执行并在当前线程(使用默认调度程序)上“内联”:

  • 任务已经启动,但是......
  • 任务当前未执行(因为任务由调度程序排队)
  • Task的调度程序(在构造时创建)与当前调度程序相同
  • 任务未取消
  • 任务没有出错

第三点是模糊 - 它可以在不同的调度程序上内联执行,但这需要其他调度程序能够立即执行它,因此它依赖于调度程序是支持它的调度程序。