Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does inlining a task occur?

After reading up on inlining in the TPL from sources like here, I got the impression that a call to Task.Wait() will start a task that hasn't yet begun (at least using the default scheduler). However, writing up a quick demo like:

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();

Causes a deadlock. TaskA gets to the taskB.Wait() line, but taskB is never started. I haven't messed with the scheduler or anything, so I'm not really sure why the .Wait() call on taskB wouldn't cause it to start.

like image 420
Jordan0Day Avatar asked Dec 03 '22 06:12

Jordan0Day


2 Answers

Wait() does not cause a task to Start(). If you call Wait() on an unstarted task, it will wait for it to begin and complete until it completes, the wait timed out or the wait is cancelled. Since your call to Wait() does not contain a cancellation token or timeout, it's an infinite for the task to complete.

I think what's confusing you from the blog is this line:

However, if it hasn’t started executing, Wait may be able to pull the target task out of the scheduler to which it was queued and execute it inline on the current thread.

The key here is the phrase "hasn't started executing". This does not mean that Start() was not called, but that Start() was called, which schedules the task and makes it ready to execute, but the task hasn't begun to execute.

Start() is necessary to schedule a task for execution, it doesn't immediately begin execution. That's the main point of that blurb. If the task is ready to go but not scheduled, it may be inlined. But it won't start a task that hasn't even been scheduled.

If you look at TaskStatus in the MSDN (See here) you see the following values:

  • Created
  • WaitingForActivation
  • WaitingToRun
  • Running
  • WaitingForChildrenToComplete
  • RanToCompletion
  • Canceled
  • Faulted

When you create the task (with new or factory), it is in Created state. Nothing happens to a task in this state. Once it is started, then it moves to WaitingForActivation and so on, at THIS point until it reaches Running, its possible according to that blog that it could be inlined.

So, long story short, creating a task just puts it in Created state and won't make it start if Wait() is called. Make sense?

like image 130
James Michael Hare Avatar answered Dec 13 '22 05:12

James Michael Hare


The inlining mentioned in that article is different than a Task starting. Waiting on a task does not start it - which can be demonstrated very easily. Just try the following:

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();
        }
    }
}

You'll see that the task never starts...

A call to task.Wait() will not start a task. It will cause the Task to execute immediately and "inline" on the current thread (with the default scheduler) if:

  • The Task has been started, but...
  • The Task is not currently executing (since Tasks get queued by the scheduler)
  • The Task's scheduler (created at construction) is the same scheduler as the current one
  • The Task isn't canceled
  • The Task isn't faulted

The third point there is fuzzy - it can execute inline on a different scheduler, but this requires the other scheduler to be able to execute it immediately, so it's dependent on the scheduler being one that supports this.

like image 28
Reed Copsey Avatar answered Dec 13 '22 06:12

Reed Copsey