Шаблон повторного входа 5: отмена предыдущего вызова

Мне нужна задача повторного ввода и реализации кода, аналогичного https://blogs.msdn.microsoft.com/lucian/2014/03/03/async-re-entrancy-and-the-patterns-to-deal-with-it/ (шаблон 5)

но мне интересно, если распоряжение CancellationTokenSource не отсутствует. Моя реализация добавляет его в.ContinueWith

    private Task _fooAsyncTask;
    private CancellationTokenSource _fooAsyncCancellation;

    public async Task Button1Click()
    {
        // Assume we're being called on UI thread... if not, the two assignments must be made atomic.
        // Note: we factor out "FooHelperAsync" to avoid an await between the two assignments. 
        // without an intervening await. 
        _fooAsyncCancellation?.Cancel();
        _fooAsyncCancellation = new CancellationTokenSource();
        _fooAsyncTask = FooHelperAsync(_fooAsyncCancellation.Token);

        await _fooAsyncTask.ContinueWith(task =>
        {
            _fooAsyncCancellation.Dispose();
            _fooAsyncCancellation = null;
        });
    }

    private async Task FooHelperAsync(CancellationToken cancel)
    {
        try { if (_fooAsyncTask != null) await _fooAsyncTask; }
        catch (OperationCanceledException) { }
        cancel.ThrowIfCancellationRequested();
        await FooAsync(cancel);
    }

    private async Task FooAsync(CancellationToken cancel)
    {
        //
    }

Это верно?

1 ответ

Вы должны изменить свой код на

  • установить _fooAsyncCancellation в null в потоке пользовательского интерфейса (в продолжение это не так)
  • гарантировать, что вы располагаете CTS, созданным для этой задачи.

Вот модифицированный код

Task _fooAsyncTask;
CancellationTokenSource _fooAsyncCancellation;

async void button1_Click(object sender, EventArgs e)
{
    _fooAsyncCancellation?.Cancel();
    using (var cts = new CancellationTokenSource())
    {
        _fooAsyncCancellation = cts;

        try
        {
            await FooAsyncHelper(cts.Token);
        }
        catch (OperationCanceledException) { }

        if (_fooAsyncCancellation == cts)
        {
            _fooAsyncCancellation = null;
        }
    }
}

async Task FooAsyncHelper(CancellationToken cancellationToken)
{
    try
    {
        if (_fooAsyncTask != null)
        {
            await _fooAsyncTask;
        }
    }
    catch (OperationCanceledException) { }
    cancellationToken.ThrowIfCancellationRequested();
    await FooAsync(cancellationToken);
}

async Task FooAsync(CancellationToken cancellationToken)
{
    // just some sample work to do
    for (int i = 0; i < 100; i++)
    {
        await Task.Delay(100);
        cancellationToken.ThrowIfCancellationRequested();
    }
}
Другие вопросы по тегам