Как гарантировать, что CancellationTokens будет обновляться?


Microsoft приводит этотпример использования CancellationToken в .NET 4.

using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {

        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Factory.StartNew(() =>
        {

            // Were we already canceled?
            ct.ThrowIfCancellationRequested();

            bool moreToDo = true;
            while (moreToDo)
            {
                // Poll on this property if you have to do
                // other cleanup before throwing.
                if (ct.IsCancellationRequested)
                {
                    // Clean up here, then...
                    ct.ThrowIfCancellationRequested();
                }

            }
        }, tokenSource2.Token); // Pass same token to StartNew.

        tokenSource2.Cancel();

        // Just continue on this thread, or Wait/WaitAll with try-catch:
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }

        Console.ReadKey();
    }
}

Однако, мое понимание заключается в том, что если переменная изменяется в одном потоке, другой поток может не получить измененное значение из-за кэширования. И поскольку CancellationToken отменяется в главном потоке, как поток Task может быть уверен, что CancellationToken, который он проверяет, действительно является актуальным?

Почему невозможно, чтобы Task считывал кэшированное значение жетон?

Примечание: моя мотивация в вопросе об этом возникает из вопроса, нужно ли мне, чтобы мои переменные экземпляра CancellationToken были volatile.

1 5

1 ответ:

Это обрабатывается внутри CancellationTokenSource. Частная переменная, используемая для отслеживания состояния CTS, помечена как volatile, что предотвращает устаревание внутренней проверки состояния.

Моя мотивация в вопросе об этом возникает из вопроса, нужно ли мне, чтобы переменные экземпляра CancellationToken были изменчивыми.

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

В основном, когда вы создаете CancellationToken начиная с CancellationTokenSource, маркер содержит ссылку на исходный источник. Эта ссылка никогда не может измениться, поэтому вызов ThrowIfCancellationRequested проверяет состояние источника внутренне. Поскольку исходное состояние само по себе volatile, оно никогда не бывает "устаревшим".