2

Using a CancellationTokenSource on a task thats acquires a lock

If the thread acquires the lock when the cancelation occures, it does not release the lock

BTW, the thread needs to stop immediately, without finnishing the work

This is an example for such a code:

var cancellationTokenSource = new CancellationTokenSource;

Task.Run(new Action (() => 
{ 
    while(true)
    {
        lock (locker)
        {
            DoSomething();    
        }

        DoAnotherThing();

        Task.Delay(1000, cancellationTokenSource.Token);    
    }
}), cancellationTokenSource.Token);

I've found several ways to handle it, but I've wanted to hear some suggestions

Thanks

EDIT: To answer @spender question, this is the implementation a thought of (shortened) :

    object locker = new object();
    var cancellationTokenSource = new System.Threading.CancellationTokenSource;
    var token = cancellationTokenSource.Token;

    Task.Run(new Action (() => 
    { 


        while(true)
        {
            lock (locker)
            {
                using (token.Register(() => token.ThrowIfCancellationRequested()))
                {
                    break;
                };

                DoSomething();    
            }

            DoAnotherThing();

            Task.Delay(1000, cancellationTokenSource.Token);    
        }
    }), cancellationTokenSource.Token);
Guy Levin
  • 1,230
  • 1
  • 10
  • 22

1 Answers1

0

You're never allowing your payload action to complete. Cancelling a running task does is not the same as calling Thread.Abort (which you wouldn't want to do anyway). You need to propagate cancellation to anything that is likely to continue executing/waiting/blocking for any significant time after you signal cancellation.

while(!cancellationTokenSource.Token.IsCancellationRequested)
{
    lock (locker)
    {
        DoSomething(); //consider passing the token here if it takes a while...
    }

    DoAnotherThing(); //and here...
    try
    {
        Task.Delay(1000, cancellationTokenSource.Token);    
    }
    catch(TaskCanceledException)
    {
        break;
    }
}
spender
  • 117,338
  • 33
  • 229
  • 351
  • Thank you, but it does not answer my question. I need the Task to stop immediately, not wait for it to finish – Guy Levin Sep 15 '14 at 09:25
  • 2
    @GuyLevin : It's not possible to stop a task immediately. The only option to do this is Thread.Abort. [Thread.Abort is an abomination](http://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort) that should never have been included. – spender Sep 15 '14 at 09:28
  • 1
    @GuyLevin There is no magic bullet allows you to cancel immediately, You need to check cancellation requested time to time and throw. – Sriram Sakthivel Sep 15 '14 at 09:28
  • 1
    @spender even with thread.abort it is not assured that the thread stops immediately. Thus in total one can say if a thread needs to stop IMMEDIATELY then the application has a problem with the design (stumbled upon that problem myself quite a few times by now sadly no workaround possible). GuyLevin if you need to stop it ASAP you need to check for the cancellationtoken in what you are doing every few lines of codes or every iteration (like spender mentioned in the comment for DoSomething() and also DoAnotherThing()). – Thomas Sep 15 '14 at 09:32
  • So, What you are saying is that cancelationtoken does not realy cancel the task? it waits for it to finnish? in the case mentioned above, the while(true) will run forevere? – Guy Levin Sep 15 '14 at 09:38
  • 2
    @GuyLevin : Yes, the while true will run forever. Cancellation token is generally used for signalling to an **async** task to complete early. This is mainly in I/O scenarios. There's no magic. The implementation of the task of which you are requesting cancellation must be programmed too deal with it. It's not difficult to pass a token around, and it's a pretty handy thing to have a single place that can cancel lots of different behaviours. – spender Sep 15 '14 at 09:44
  • Can you add an example of the use you mentioned with async? – Guy Levin Sep 15 '14 at 10:10
  • @GuyLevin, there's one in the code... `Task.Delay` can take a second token parameter which cancels the task early. Most async methods in the BCL take this approach. Perhaps a [read of the docs](http://msdn.microsoft.com/en-us/library/dd997289%28v=vs.110%29.aspx) might prove enlightening. – spender Sep 15 '14 at 10:13
  • Oh you meant on methods like Task.Delay I thought you meant there is some special way to use it on user implemented async methods – Guy Levin Sep 15 '14 at 10:17