Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
576 views
in Technique[技术] by (71.8m points)

c# - Stopping a task without a CancellationToken

I am using an external library that has async methods, but not CancellationToken overloads.

Now currently I am using an extension method from another StackOverflow question to add a CancellationToken:

    public async static Task HandleCancellation(this Task asyncTask, CancellationToken cancellationToken)
    {
        // Create another task that completes as soon as cancellation is requested. http://stackoverflow.com/a/18672893/1149773
        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
        cancellationToken.Register(() =>
            tcs.TrySetCanceled(), useSynchronizationContext: false);
        Task cancellationTask = tcs.Task;

        // Create a task that completes when either the async operation completes, or
        // cancellation is requested.
        Task readyTask = await Task.WhenAny(asyncTask, cancellationTask);

        // In case of cancellation, register a continuation to observe any unhandled exceptions
        // from the asynchronous operation (once it completes). In .NET 4.0, unobserved task
        // exceptions would terminate the process.
        if (readyTask == cancellationTask)
            asyncTask.ContinueWith(_ => asyncTask.Exception,
                TaskContinuationOptions.OnlyOnFaulted |
                TaskContinuationOptions.ExecuteSynchronously);

        await readyTask;
    }

However the underlying task still executes to completion. This wouldn't be much of a problem, but sometimes the underlying task never completes and consumes 99% of my CPU.

Is there any way to "kill" the task without killing the process?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I am using an extension method from another StackOverflow question

That code is very old.

The modern AsyncEx approach is an extension method Task.WaitAsync, which looks like this:

var ct = new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token;
await myTask.WaitAsync(ct);

I like how the API ended up because it's more clear that it's the wait that is cancelled, not the operation itself.

Is there any way to "kill" the task without killing the process?

No.

The ideal solution is to contact the authors of the library you're using and have them add support for CancellationToken.

Other than that, you're in the "cancel an uncancelable operation" scenario, which can be solved by:

  • Putting the code in a separate process, and terminating that process on cancellation. This is the only fully safe but most difficult solution.
  • Putting the code in a separate app domain, and unloading that app domain on cancellation. This is not fully safe; terminated app domains can cause process-level resource leaks.
  • Putting the code in a separate thread, and terminating that thread on cancellation. This is even less safe; terminated threads can corrupt program memory.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...