首页 > 解决方案 > 在没有冗余 CancellationTokenSource 的情况下链接两个 CancellationToken

问题描述

在获得CancellationToken( StartAsync) 的方法中,我想添加一个内部CancellationToken函数,以便调用者可以在外部或内部(例如通过调用AbortAsync()方法)取消异步操作。

AFAIK,这样做的方法是使用CreateLinkedCancellationTokenSource. 但它的 API 似乎相当不舒服,因为我需要为此创建两个额外CancellationTokenSource的实例,并且因为它们实现了IDisposable,我也必须不要忘记处置它们。因此,我需要将它们都存储为成员以供以后处理。

我错过了什么吗?我觉得应该有一种更简单的方法可以将额外的取消机制附加到现有令牌上,而不会强迫我维护两个CancellationTokenSource实例。

public Task StartAsync(CancellationToken externalToken)
{
    this.actualCancellation = new CancellationTokenSource();
    this.linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(
        actualCancellation.Token, externalToken);
    this.execution = this.ExecuteAsync(this.linkedCancellation.Token);
    return this.execution;
}

public async Task AbortAsync()
{
    try
    {
        this.actualCancellation.Cancel();
        await this.execution;
    }
    catch
    {
    }
    finally
    {
        this.actualCancellation.Dispose();
        this.linkedCancellation.Dispose();
    }
}

标签: c#.net-coretask-parallel-librarycancellationtokensource

解决方案


链接取消源不是一种特殊的取消源。它是一个常规的取消源,也“链接”到现有令牌 - 即,当现有令牌被取消时,源将被取消。在所有其他方面,它是一个正常的取消源,因此您可以像任何其他取消源一样自行取消它。

因此,您只需要一个取消源 - 一个链接到现有令牌并且也可以手动取消的源:

public Task StartAsync(CancellationToken externalToken)
{
    this.linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(externalToken);
    this.execution = this.ExecuteAsync(this.linkedCancellation.Token);
    return this.execution;
}

public async Task AbortAsync()
{
    try
    {
        this.linkedCancellation.Cancel();
        await this.execution;
    }
    catch
    {
    }
    finally
    {
        this.linkedCancellation.Dipose();
    }
}

顺便说一句,我会仔细考虑这种 API 设计的生命周期问题。目前StartAsync做资源分配和AbortAsync清理;我推荐一种由构造函数和Dispose(RAII)处理的设计。


推荐阅读