Stopping a task without a CancellationToken

后端 未结 3 1571
我寻月下人不归
我寻月下人不归 2020-12-19 04:22

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

Now currently I am using an extension method fr

相关标签:
3条回答
  • 2020-12-19 04:44

    The only way I can think of is to change the TaskScheduler and mange the creation of the threads that are used for the tasks yourself. That is a lot of work.

    The basic concept is to create your own implementation of the TaskScheduler, start a new task with your own scheduler assigned. This way you get your scheduler to be the current one and start your problematic task from this task.

    There are still reason that may not work. If the task causing you trouble creates more tasks using the default task scheduler you still got the same problem. (Task.Run does so)

    How ever if they are using the async/await key words your scheduler will remain active.

    Now with the scheduler under your own control, you can kill any task by using Thread.Abort.

    To get a idea about the implementation afford, you should have a look at the ThreadPoolTaskScheduler. That is the default implementation of the scheduler.

    As I said this is a lot of work, but the only way I can think of to kill task that can't be cancelled.

    To get a test running if that even works at all you may only want to implement the behaviour the ThreadPoolTaskScheduler has for the TaskCreationOptions.LongRunning option. So spawning a new thread for each task.

    0 讨论(0)
  • 2020-12-19 04:45

    As you suggest you can cancel a task by passing in a CancellationToken and then calling Cancel.

    As for how you'd go about triggering that cancellation depends on the nature of your application.

    A few possible scenarios

    1. Carry on until you click cancel
    2. Cancel after a fixed time
    3. Cancel if there's been no progress for a fixed time

    In case 1 you simply cancel the task from your cancel button, for example

    private void cancel_Click(object sender, RoutedEventArgs e)
    {
        ...
        cts = new CancellationTokenSource();
        await MyAsyncTask(cts.Token);
        cts.Cancel();
        ...
    }
    

    In case 2 you could start a timer when you start your task and then cancel the task after a set time using CancelAfter, for example

    private void start_Click(object sender, RoutedEventArgs e)
    {
        ...
        cts = new CancellationTokenSource();
        cts.CancelAfter(30000);
        await MyAsyncTask(cts.Token);
        ...
    }
    

    In case 3 you could do something with progress, for example

    private void start_Click(object sender, RoutedEventArgs e)
    {
        ...
        Progress<int> progressIndicator = new Progress<int>(ReportProgress);
        cts = new CancellationTokenSource();
        await MyAsyncTask(progressIndicator, cts.Token);
        ...
    }
    
    void ReportProgress(int value)
    {
        // Cancel if no progress
    }
    

    Here are a few useful links Parallel programming, task cancellation, progress and cancellation, cancel tasks after set time, and cancel a list of tasks.

    0 讨论(0)
  • 2020-12-19 05:02

    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.
    0 讨论(0)
提交回复
热议问题