Providing cancellation if polling CancellationToken is not possible

后端 未结 1 381
孤城傲影
孤城傲影 2021-01-21 14:18

Here\'s a (silly) example of a method that blocks the caller\'s thread but does not support cancellation:

Public Sub WorkUntil5()
    Threading.SpinWait.SpinUnti         


        
相关标签:
1条回答
  • 2021-01-21 15:11

    Let's rephrase the question. You have a non-cancelable operation called WorkUntil5 which you want to cancel. How can you do that?

    Stephen Toub discusses this scenario in "How do I cancel non-cancelable async operations?".

    The only real solution is to fix WorkUntil5 so that it allows cancellation. If that isn't possible (why?), you have to decide what you mean by "cancellation"?

    Do you want to:

    1. Really cancel the long operation, or do you want to
    2. Stop waiting for it?

    Both operations are unreliable because you have no way to know what was left unfinished in the long-running method. It's not a problem with the design of the TPL but the design of the long-running method.

    Operation #1 isn't really possible, since the method doesn't provide any way to cancel it.

    Operation #2 can be handled using Tasks and the TaskCompletionSource but isn't very reliable, because you have no way of knowing if the long operation left garbage behind or terminated with an exception.

    Stephen Toub shows how to do this and even provides an extension method to do that:

    public static async Task<T> WithCancellation<T>( 
    this Task<T> task, CancellationToken cancellationToken) 
    { 
        var tcs = new TaskCompletionSource<bool>(); 
        using(cancellationToken.Register( 
                s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs)) 
            if (task != await Task.WhenAny(task, tcs.Task)) 
                throw new OperationCanceledException(cancellationToken); 
        return await task; 
    }
    
    0 讨论(0)
提交回复
热议问题