TaskCanceledException:取消或超时?

TaskCanceledException: Cancel or timeout?

我只想使用 CancellationTokenSource 进行超时和取消处理。

如何区分TaskCanceledException是超时还是手动取消?

这是一个简化的例子。在实际程序中,我既不知道是否使用了 CancellationTokenSource .CancelAfter() 也不知道是否有人调用 CancellationTokenSource.Cancel()

static CancellationTokenSource cts = new CancellationTokenSource();

static void Main(string[] args)
{
    Task.Run(async () =>
    {
        try
        {
            await SomeClass.DoSomething(cts.Token);
        }
        catch (TaskCanceledException ex)
        {
            //How to find out if the exception occured due to timeout or a call to cts.Cancel()
        }
    });

    while (true)
    {
        Thread.Sleep(100);

        if (someCondition)
            cts.Cancel();
    }
}

public class SomeClass
{
    public static async Task DoSomething(CancellationToken ct)
    {
        using (var innerCts = CancellationTokenSource.CreateLinkedTokenSource(ct))
        {
            innerCts.CancelAfter(1000);

            //Simulate some operation
            await Task.Delay(10000, innerCts.Token);
        }
    }
}

谢谢

汤姆

据我所知,这是最常用的模式:

Task.Run(async () =>
{
    try
    {
        await SomeClass.DoSomething(cts.Token);
    }
    catch (OperationCanceledException) when (cts.IsCancellationRequested)
    {
        // cts cancellation occurred
    }
    catch (OperationCanceledException)
    {
        // Timeout occurred
    }
});

另一个想法是更改 SomeClass.DoSomething 方法的实现,假设您被允许这样做,以便在超时的情况下抛出 TimeoutException 而不是 OperationCanceledException.

public static async Task DoSomething(CancellationToken cancellationToken)
{
    using var innerCts = new CancellationTokenSource(millisecondsDelay: 1000);
    using var linkedCts = CancellationTokenSource
        .CreateLinkedTokenSource(cancellationToken, innerCts.Token);

    try
    {
        // Simulate some operation
        await Task.Delay(10000, linkedCts.Token);
    }
    catch (OperationCanceledException) when (innerCts.IsCancellationRequested)
    {
        throw new TimeoutException();
    }
}