1

I am looking for a way to cancel a task that was already started and then restart the same task with new input data.

Below is the sample code which I have written but it is not working.

private CancellationTokenSource _cancellationTokenSource;
public public async Task DoSomething(string input)
{
    _cancellationTokenSource.Cancel(true);
    _cancellationTokenSource = new CancellationTokenSource();
    try
    {

        Task.Run(async () =>
        {
            //Asynchronous method code here which uses input like database operations.
            await doSomeDataBaseOperationAsync(input);
        }, _cancellationTokenSource.Token);
    }
    catch { }
}

Can someone help me with it?

  • 4
    Cancellation is hand made; you have to check you token state to see if a cancellation has been requested, and do whatever you have to to actually cancel. – Kilazur Oct 20 '16 at 10:44
  • What is not working? The place from where you are calling `DoSomething` you can simply call `_cancellationTokenSource.Cancel(true);` which will cancel the task and then call the method again. Is it not working? – RBT Oct 20 '16 at 10:44
  • `cancellationTokenSource.Cancel(true);` this code before initialization, does it work ? – Mrinal Kamboj Oct 20 '16 at 10:45
  • Also what is that `cancellationTokenSource` variable inside `DoSomething` method? It doesn't seem to be defined anywhere in your code block. – RBT Oct 20 '16 at 10:46
  • Basically my doSomeDataBaseOperationAsync(input) is still getting executed with old input and then starts with new input. – Suraj Mittal Oct 20 '16 at 10:46
  • It is defined just outside the function block in my class. – Suraj Mittal Oct 20 '16 at 10:48
  • No worries. Just update your code snippet to correct it. – RBT Oct 20 '16 at 10:48
  • yes @RBT it is not working. – Suraj Mittal Oct 20 '16 at 10:50
  • @MrinalKamboj this is to cancel the previous instance of the Task that was already running. – Suraj Mittal Oct 20 '16 at 10:52
  • @SurajMittal, when do you cancel next ? Also Why re-initialization, then ? – Mrinal Kamboj Oct 20 '16 at 10:55
  • @MrinalKamboj I'm trying to cancel when the DoSomething method is called again basically if I have a code like `DoSomething("hello"); DoSomething("while"); ` then the one with hello as input parameter should get cancelled when the DoSomething("while") starts executing... – Suraj Mittal Oct 20 '16 at 10:56
  • You don't need this code, as Token Source is already initialized `_cancellationTokenSource = new CancellationTokenSource();` – Mrinal Kamboj Oct 20 '16 at 11:02
  • When you say not working, what happens, what is your expectation, which is not met ? – Mrinal Kamboj Oct 20 '16 at 11:05
  • @MrinalKamboj `DoSomething("hello"); ` is not cancelled when executing `DoSomething("while"); ` – Suraj Mittal Oct 20 '16 at 11:08
  • Ok that is mostly due to your code design, where you even create a new object for the `CancellationTokenSource` – Mrinal Kamboj Oct 20 '16 at 11:10
  • @MrinalKamboj if I do not create a `new CancellationTokenSource()` then the previous task remains cancelled and I am not able to restart the task again. That is why I have to create a new cancellation token. – Suraj Mittal Oct 24 '16 at 07:02
  • Check the solution that I have posted, yes if you want to create a new Task with same Canceled token, then better Dispose and recreate, though in practice, not a very good thing. Ideally, you should assign a separate Token to each task and thus freely operate them, instead of worrying about one impacting multiple instances – Mrinal Kamboj Oct 24 '16 at 07:49
  • Check - http://stackoverflow.com/a/9332634/1559611 Also let me know if my solution helps you in any better understanding of the concept, else I would delete, as there's no point gathering anonymous down vote – Mrinal Kamboj Oct 24 '16 at 08:01

1 Answers1

0

You need to make a manual check in your method doSomeDataBaseOperationAsync which is getting executed asynchronously as shown in the code snippet below. The way I usually do is check the state of the cancellation token source once at the starting of the method itself. If cancellation is not requested till that time then just go ahead and execute the entire function body.

But nobody can stop you from making that check at more critical junctures or milestones inside your method e.g. you might want to recheck the cancellation token state once before firing the DB call as well.

Word of Caution: You just need to make sure that whenever you make such a check several time during the execution of the method and returning mid way then you aren't leaving the state of your object in an inconsistent state. If you don't alter any member variables of your class in such a method then you should be good.

private void doSomeDataBaseOperationAsync(input)
{
   if (_cancellationTokenSource.IsCancellationRequested)
     return; //stop any further processing.
   //do some processing and calculations on the client side
   //.....
   //.....
   //.....
   //make a check again before firing DB request
   if (_cancellationTokenSource.IsCancellationRequested)
     return; //stop any further processing.
   //Do database stuff. cancellation has not been requested. Process the DB request.
}
RBT
  • 24,161
  • 21
  • 159
  • 240
  • Doesn't the CancellationTokenSource.Cancel() event get propagated all the way through the task? – Suraj Mittal Oct 20 '16 at 11:07
  • Why would you check this in a Task, with cancellation Token supplied, it will Automatically Cancel, this has to be in the Caller to check the Cancellation of a Task started in the Async mode. – Mrinal Kamboj Oct 20 '16 at 11:07
  • @SurajMittal You are right, just check it `IsCancellationRequested` from outside – Mrinal Kamboj Oct 20 '16 at 11:08
  • @RBT what if my `doSomeDataBaseOperationAsync()` contains only the database code and nothing else? – Suraj Mittal Oct 20 '16 at 11:13
  • @SurajMittal You just check it once at the starting of the execution of the method body. If cancellation hasn't been requested then contact your DB and fire your queries. You won't be able to stop the DB request mid-way there after.From your few comments I'm able to gauge that you are looking for something as if the thread/method should get immediately aborted by the CLR as soon as the cancellation token is set. That is not a possibility if you are expecting anything like that. TPL believes in the philosophy of cooperative/graceful termination. `Thread.Abort` API is a thing of the past now. – RBT Oct 20 '16 at 11:28
  • Thanks @RBT that clarifies a lot since it is exactly the functionality I was looking for. – Suraj Mittal Oct 20 '16 at 11:33
  • Glad that it helped. @SurajMittal You can explore my blog [here](http://www.codeproject.com/Articles/1083787/Tasks-and-Task-Parallel-Library-TPL-Multi-threadin) if you want to explore the TPL internals, behavior and fundamentals further. – RBT Oct 20 '16 at 11:36
  • @RBT That's not how it works, yes DB request will be Asynchronously dispatched, but Task cancellation means an in transaction request (DML) would be rolled back and for Select request, caller is no more available to receive the result. You still don't check the way you have done, what if it gets canceled post you have checked and dispatched the request, same issue isn't it – Mrinal Kamboj Oct 20 '16 at 11:47
  • @MrinalKamboj so basically is there no way to perform `Thread.Abort()` with `Task` API's or is there any other alternative with using `Task`? – Suraj Mittal Oct 24 '16 at 07:04