0

Background: I have the application which can run algorithms for calculating. Before running an algorithm task, we start an alive task which observes the algorithm is not terminated. If the alive task is terminated, we send a cancellation to the algorithm task and try to stop it via a method which called between code blocks, so we cannot stop the algorithm task immediately.

At the current moment, we use such block of code to check alive task or not:

TaskTokenSource = new CancellationTokenSource();
TaskToken = TaskTokenSource.Token;

IsAliveTokenSource = new CancellationTokenSource();
IsAliveToken = IsAliveTokenSource.Token;

Task.Run(async () =>
{
    while (true)
    {
        var isAlive = TaskAction.GetStatus(TaskId);
        Log.Info($"Task status {isAlive.ToDbAttribute()}");
        if (isAlive == TaskStatuses.Cancelling)
        {
            TaskTokenSource.Cancel();
            IsAliveTokenSource.Cancel();
        }

        await Task.Delay(10000);
        if(IsAliveToken.IsCancellationRequested)
        {
            Log.Info($"End heartbeat task {TaskId}");
            IsAliveToken.ThrowIfCancellationRequested();
        }
    }
});

And this method which check the task is terminated between code blocks

public void IsContinue()
{
    if (TaskToken.IsCancellationRequested)
        TaskToken.ThrowIfCancellationRequested();
}

I try to emulate other logic in console application to generate OperationCanceledException, but it cannot generate exception like I want. Can you say how to generate OperationCanceledException immediately, or describe why the logic is not working?

CancellationTokenSource IsAliveTokenSource;
CancellationToken IsAliveToken;

IsAliveTokenSource = new CancellationTokenSource();
IsAliveToken = IsAliveTokenSource.Token;

try
{
    //Check the task is alive
    Task.Run(async () =>
    {
        //Placeholder to simulate task terminate
        int attempts = 0;
        bool isAlive = true;
        while (true)
        {
            //Placeholder generates the task status is not alive
            if (attempts == 3)
                isAlive = false;
            attempts++;

            //isAlive = TaskActions.CheckStatus(TaskId);
            Console.WriteLine($"Task status: {isAlive}");
            if (!isAlive)
                IsAliveTokenSource.Cancel();

            await Task.Delay(10000);

            //Stop checking task status
            if (IsAliveToken.IsCancellationRequested)
                IsAliveToken.ThrowIfCancellationRequested();
        }
    });

    //Other part of codes
    //How to generate OperationCanceledException here ?
    Console.ReadLine();
}
catch (OperationCanceledException)
{
    Console.WriteLine("Task is terminated");
}
catch (Exception ex)
{
    Console.WriteLine(ex);
}

Bushuev
  • 557
  • 1
  • 10
  • 29
  • 1
    What you are trying to do in essence is to abort a `Task` in a [non-cooperative](https://stackoverflow.com/questions/57171975/using-a-cancellationtoken-to-cancel-a-task-without-explicitly-checking-within-th) fashion, correct? – Theodor Zoulias Nov 27 '21 at 19:05
  • 1
    An exception occurred in a task won't propagate in to main thread unless you await that task. – Eldar Nov 27 '21 at 19:06
  • You may check [this](https://stackoverflow.com/questions/12980712/what-is-the-best-way-to-catch-exception-in-task/12981091) question. – Eldar Nov 27 '21 at 19:06
  • @TheodorZoulias, yes. In old version of .net I use ThreadAbortException, but now I want to make better solution which сorresponds to the current approach through tasks. – Bushuev Nov 27 '21 at 19:13
  • 1
    Just a note that you don't need to check `IsCancellationRequested` if you are calling `ThrowIfCancellationRequested` already – Luke Vo Nov 27 '21 at 19:54
  • @LukeVo, You are right, in this example I needed to remove it before publishing, but usually we write an info message to log about actions at the system, so this is my bad habit. – Bushuev Nov 27 '21 at 20:18
  • What type is the `Task` that you want to abort non-cooperatively? Is it a delegate-based task, created with the `Task.Run` method, or a promise-style task, created from an `async` method? In case it's a delegate-based task, does it include recurrent `Thread.Sleep`s (or `WaitOne`s on some [wait handle](https://learn.microsoft.com/en-us/dotnet/api/system.threading.waithandle)) as part of the calculation, or it's non-stop (uninterrupted) calculation from start to finish? – Theodor Zoulias Nov 28 '21 at 08:52
  • @TheodorZoulias It is the async-await method, in which we can create some child tasks which calculate data by using different scenarios. Some of these tasks can calculate some seconds (users want to see what happen for one-two scenarios), but other tasks can calculate a half of an hour. All tasks have ends. I suggest in my case it is normal to ask the host that the task is terminated periodically. – Bushuev Nov 28 '21 at 17:13
  • Bushuev aborting in-process non-cancelable async APIs is absolutely impossible. You can't even stop them by aborting a thread, because async operations [do not run on threads](https://blog.stephencleary.com/2013/11/there-is-no-thread.html). The only workaround is to invoke them on a separate process, and then kill the process to abort them. In that case you'll have to deal with inter-process communication though. – Theodor Zoulias Nov 29 '21 at 00:28
  • 1
    @TheodorZoulias, yes, you are fully right. I am reading the book by Stephen Cleary "Concurrency in a C # Cookbook" at the current moment. – Bushuev Nov 29 '21 at 18:31

0 Answers0