Cancel task by time

断了今生、忘了曾经 提交于 2019-12-01 18:15:32

You can get the same results as your original "abort" version by using the same timings. For example, this code:

static void Main()
{
    var clt = new CancellationTokenSource();
    clt.CancelAfter(1000);
    for (int i = 0; i < 10; i++)
    {
        Task.Run(() => Do(clt.Token));
    }
    Console.ReadLine();
}

private static void Do(CancellationToken cltToken)
{
    Console.WriteLine("Start " + Task.CurrentId);
    Thread.Sleep(2000);

    if (!cltToken.IsCancellationRequested)
    {
        Console.WriteLine("End " + Task.CurrentId);
    }
    else
    {
        Console.WriteLine("Cancelled "+ Task.CurrentId);
    }
}

Will produce something simliar to:

Start 111
Start 112
Start 113
Start 114
Start 115
Start 116
Start 117
Start 118
Start 119
Start 120
Cancelled 111
Cancelled 112
Cancelled 118
Cancelled 116
Cancelled 114
Cancelled 113
Cancelled 117
Cancelled 115
Cancelled 119
Cancelled 120

Using a CancellationTokenSource is a better option than aborting threads. Thread.Abort is a bad idea since it aborts the thread without providing proper cleanup mechanisms. Using the token allows you to cooperatively handle the cancellation in a clean manner.

As for why your other options were not functioning properly - The timings you used were a bit too close together. This is especially an issue when running under the debugger, as it will prevent the timings (ie: CancelAfter as well as Thread.Sleep) from firing at the same time. If you run a release build outside of the Visual Studio host process, you'll likely find that they work far more reliably.

First, the issue you are seeing where the cancellation token is not signaled is probably due to subtle timing variations. CancelAfter should work fine, but you will need to increase the difference between the timeout and the sleep to get a more realistic of picture of what will happen.

Second, and I may be the harbinger of bad news here, but if this unmanaged resource does not offer mechanisms for gracefully terminating an operation then this just got exponentially harder. The reasons are:

  • Obviously there is no way to poll the CancellationToken while a thread is executing unmanaged code. So there is no way to initiate a gracefully shutdown on your own.
  • Aside from the fact that you should not be aborting a thread anyway the Thread.Abort call will not inject the abort signal into the target until it rejoins the managed realm. In other words, aborts will not terminate threads that are executing unmanaged code. This was done intentionally to make aborts safer.

The only way to make this happen reliably is to run the unmanaged resource out-of-process. That means you will need to spin up a new process to execute the unmanaged code and then use WCF (or other communication protocol) to send messages/data back and forth. If the unmanaged resource does not respond in a timely manner then you can kill the process. This is safe because killing another process does not corrupt the state of the current process.

Hopefully whatever unmanaged resource it is you are using has an API with a gracefully termination mechanism built into it. If it is well written it might have such a feature, but my experience has shown that many do not.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!