Библиотека TPL C#. Отмена задач

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Отмена задач может потребоваться по различным причинам — долгое выполнение задач, отмена выполнения каких-либо действий, в случае, если задача завершилась с ошибкой и так далее. В TPL предусмотрена возможность отмены параллельных задач с использованием специального объекта — CancellationToken.

Пример отмены параллельной задачи

В рассматриваемом примере, в параллельной задаче определяются простые числа. В случае, если пользователь вводит в консоль символ «N«, выполнение задачи прерывается.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskCancel
{
    internal class Program
    {
        static CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
        static CancellationToken token = cancelTokenSource.Token;

        static void Main(string[] args)
        {
            Task<int> primeTask = new Task<int>(() => TaskMethod(), token);
            primeTask.Start();
            


            Console.WriteLine("Введите N для отмены операции");
            string s = Console.ReadLine();
            if (s.ToUpper() == "N")
                cancelTokenSource.Cancel();

            Console.WriteLine($"Обнаружено {primeTask.Result} простых чисел");

            Console.Read();
        }


        static int TaskMethod()
        {
            int count = 0;
            int i = 2;
            while (!token.IsCancellationRequested)
            {
                if (IsPrime(i))
                {
                    count++;
                    Console.Write($"{i} ");
                }
                i++;
                Thread.Sleep(100); 
            }
            Console.WriteLine($"Операция отменена.");
            return count;

        }
        public static bool IsPrime(int number)
        {
            for (int i = 2; i < number; i++)
            {
                if (number % i == 0)
                    return false;
            }
            return true;
        }
    }
}

Для того, чтобы получить возможность прерывать выполнение параллельной задачи, нам необходимо создать токен отмены. Для этого, мы вначале создаем объект:

static CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

и, затем, получаем сам токен:

static CancellationToken token = cancelTokenSource.Token;

Полученный токен мы передаем в конструктор задачи:

Task<int> primeTask = new Task<int>(() => TaskMethod(), token);

Чтобы задача была отменена, мы, при выполнении какого-либо условия, вызываем метод Cancel() объекта CancellationTokenSource. После того, как вызван метод Cancel(), свойство токена token.IsCancellationRequested возвращает true и в методе задачи происходит прерывание цикла while.

Как только пользователь вводит с клавиатуры символ «n» и жмет Enter, задача прерывается и в консоль выводится количество найденных простых чисел.

Прерывание «спящей» задачи

В рассмотренном выше примере вызывается уже известный нам метод Thread.Sleep(), который заставляет текущий поток уснуть на n миллисекунд. Если в примере написать следующее:

Thread.Sleep(10000);

т.е. усыпить поток на 10 секунда и попробовать остановить задачу с помощью токена отмены, то произойдет следующее: поток дойдет до строки с Thread.Sleep(10000), уснет на 10 секунд и только после этого задача будет отменена. Чтобы получить возможность остановить задачу со «спящим» потоком, можно использовать следующий подход:

static int TaskMethod()
{
    int count = 0;
    int i = 2;
    while (!token.IsCancellationRequested)
    {
        //проверяем числа                

        var canceled = token.WaitHandle.WaitOne(10000);
        if (canceled)
            break;
       // Thread.Sleep(10000); 
    }
    Console.WriteLine($"Операция отменена.");
    return count;
}

здесь свойство WaitHandle возвращает дескриптор WaitHandle, получающий сигнал при отмене токена. Класс WaitHandle инкапсулирует собственный обработчик синхронизации операционной системы и используется для представления всех объектов синхронизации в среде выполнения, которые допускают несколько операций ожидания. Метод WaitOne() (про этот метод говорилось в теме про синхронизацию потоков) блокирует текущий поток до получения сигнала объектом WaitHandle.

Теперь, если запустить пример и попробовать остановить задачу, то задача отменится сразу после того, как пользователь наберет «N» и нажмет Enter.

Итого

Для отмены параллельных задач используется специальный объект класса CancellationToken, который необходимо передавать в конструкторе задаче или в качестве параметра внешнего метода задачи. Кроме того, что объект типа CancellationToken может использоваться как обычный флаг (свойство IsCancellationRequested) отмены задачи, в этом объекте также имеется свойство WaitHandle, используя которое, можно отменять задачи в которых поток может останавливаться на определенное время.

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
guest
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии