Токены отмены C# в качестве второго аргумента задачи

Как я могу отменить длительную задачу, перенаправив токен внутри задачи, а не внутри метода, который вызывает задача?

Мой код:

class Program
{
    static void Main(string[] args)
    {
        CancellationTokenSource token = new CancellationTokenSource();
        Stopwatch stop = new Stopwatch();
        stop.Start();

        Task.Factory.StartNew(() => myLongTask(6000), token.Token);

        while (true)
        {
            Thread.SpinWait(1000);
            if (stop.ElapsedMilliseconds > 3000)
            {
                token.Cancel();
            }
        }
    }

    public static void myLongTask(int time)
    {
        var sw = Stopwatch.StartNew();
        Console.WriteLine("Task started");
        while (true)
        { }
        Console.WriteLine("Task ended");
    }
}

Эта задача никогда не отменяется. Если я пересылаю токен в методе myLongTask(), я могу непрерывно прослушивать, если отмена была вызвана, однако я не уверен... Как вы можете сделать это таким образом?


person Norgul    schedule 31.10.2016    source источник
comment
отмена является совместной. По этой причине код должен быть написан так, чтобы он осведомлялся о маркерах отмены, которые он должен учитывать.   -  person Damien_The_Unbeliever    schedule 31.10.2016
comment
Нет ли возможности сделать это иначе?   -  person Norgul    schedule 31.10.2016
comment
Альтернативой является упреждение, о чем свидетельствует, например. Thread.Abort — но это может легко привести к трудно поддающимся очистке состояниям — вот почему почти любой современный подход к отмене принимает кооперативный стиль. Так что нет, я бы не рекомендовал альтернативу - сделать код, который должен быть отменяемым, с учетом токенов отмены.   -  person Damien_The_Unbeliever    schedule 31.10.2016


Ответы (1)


Вам нужно самостоятельно проверить состояние токена, например:

public static void myLongTask(int time, CancellationToken token)
{
    var sw = Stopwatch.StartNew();
    Console.WriteLine("Task started");
    while (true)
    { 
      token.ThrowIfCancellationRequested();
    }
    Console.WriteLine("Task ended");
}

Причина этого, как упоминалось в комментариях, заключается в том, что отмена является совместным действием. Если бы это было не так, инфраструктуре пришлось бы принудительно остановить вашу задачу, и это могло бы оставить ваше приложение в нежелательном состоянии. Проверяя себя, вы имеете полный контроль над тем, что означает отмена операции.

person Sean    schedule 31.10.2016
comment
Я знаю... Я хотел бы найти способ сделать это за пределами этой функции. - person Norgul; 31.10.2016
comment
@Norgul, как вы хотите, чтобы ваша функция вела себя в случае отмены? Идея CancellationToken состоит в том, чтобы предоставить определенную отмену (что означает, что функция рабочей нагрузки должна знать о токене и обрабатывать его). - person quadroid; 31.10.2016
comment
Я хотел бы разорвать непрерывный цикл и остановить выполнение с исключением - person Norgul; 31.10.2016
comment
@Norgul Вы должны сделать это со своим кодом, потому что ни один из сторонних классов не может изменить ваш код таким образом. - person VMAtm; 31.10.2016