Когда происходит встраивание задачи? - PullRequest
4 голосов
/ 06 декабря 2011

После прочтения встраивания в 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 никогда не запускается. Я не связывался с планировщиком или чем-то еще, поэтому я не совсем уверен, почему вызов .Wait () для taskB не приведет к его запуску.

Ответы [ 2 ]

15 голосов
/ 07 декабря 2011

Wait() не вызывает задачу на Start(). Если вы вызовете Wait() для незапущенной задачи, она будет ждать начала и завершения, пока не завершится, не истекло время ожидания или ожидание не отменено. Поскольку ваш вызов Wait() не содержит токена отмены или тайм-аута, выполнение задачи бесконечно.

Я думаю, что вас смущает в блоге эта строка:

Однако, если он еще не начал выполняться, Wait может целевое задание из планировщика, к которому оно было поставлено в очередь, и выполнить он встроен в текущий поток.

Ключевым моментом здесь является фраза "еще не начал выполняться". Это не означает, что Start() не был вызван, но Start() был вызван , который планирует задачу и готовит ее к выполнению, но задача еще не начала выполняться.

Start() необходимо запланировать выполнение задачи, оно не сразу начинает выполнение. Это основной смысл этой рекламы. Если задача готова к выполнению, но не запланирована, она может быть встроена. Но это не запустит задачу, которая даже не была запланирована.

Если вы посмотрите на TaskStatus в MSDN ( См. Здесь ), вы увидите следующие значения:

  • Создано
  • WaitingForActivation
  • WaitingToRun
  • Запуск
  • WaitingForChildrenToComplete
  • RanToCompletion
  • Отменено
  • Faulted

Когда вы создаете задачу (с новой или заводской), она находится в состоянии Created. Ничего не происходит с задачей в этом состоянии. Как только он запущен, он переходит к WaitingForActivation и так далее, в ЭТОЙ точке, пока не достигнет Running, согласно этому блогу возможно, что он может быть встроен.

Итак, вкратце, создание задачи просто переводит ее в состояние Created и не запускает ее, если вызывается Wait(). Имеет смысл?

2 голосов
/ 07 декабря 2011

Вставка, упомянутая в этой статье, отличается от запуска задачи.Ожидание задачи не запускает ее - что можно очень легко продемонстрировать.Просто попробуйте следующее:

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() не запустит задачу.Это приведет к немедленному выполнению Задачи и «встроенной» в текущем потоке (с планировщиком по умолчанию), если:

  • Задача была запущена, но ...
  • Задача в настоящее время не выполняется (поскольку планировщик ставит задачи в очередь)
  • Планировщик задания (созданный при создании) является таким же планировщиком, как и текущий
  • Задача не отменена
  • Задача не является ошибочной

Третий момент - нечеткость - он может выполнять встроенный вызов в другом планировщике, но для этого требуется, чтобы другой планировщик мог выполнить его немедленно, поэтомуэто зависит от планировщика, который поддерживает это.

...