Jump to content
Fulgan

Canceling a scheduled task

Recommended Posts

I'm having an issue with a timed thread: I want to cancel it when the program stops but that doesn't seem to be working (I'm calling "Terminal(1000)" when the owning object instance is destroyed but I still have AVs when the thread execute. I suspect that this is because the owned object might never actually be destroyed (an atifact of how MVC framework works).

 

Anyway, I thought a simple sollution would be to use a cancellation token to signal when the trhead must terminate. Alas, I can't configured the timed thread to be cancelled with that token:

 

Here is the code that I use to create the timed task:

 

    if CancellationToken=nil then
      FCancel := CreateOmniCancellationToken
    else
      FCancel := CancellationToken;
    FStatsRefresher := Parallel
      .TimedTask()
      .TaskConfig(Parallel.TaskConfig.CancelWith(FCancel)) // exception here
      .Execute(
      procedure
      begin
        OnStatsRefresh(TGITSVCMiddleWareRuntimeInfo.RunningStatistics());
      end);
    FStatsRefresher.Interval := Interval;

This code raises the following exception:

 

Project WineurWebSvcGUI.exe raised exception class Exception with message 'TOmniTaskControl.CancelWith: Cancellation token can only be set before the task is started'.

 

I tried various way to solve this: calling "stop" on the object before using ConfigureTask, changing the call order: nothing worked.

 

Is there any suggestion about how to fix this?

Share this post


Link to post

As you have correctly established, stopping a thread is cooperative. Thread owner can only nicely ask the worker thread to please stop, but if the worker thread keeps working, the owner can do nothing about that (short of calling TerminateThread, but that is really a bad idea).

 

Passing cancellation token to the worker is a good approach. You can just capture `FCancel` in your code:

 

.Execute(      procedure
      begin
        OnStatsRefresh(TGITSVCMiddleWareRuntimeInfo.RunningStatistics(FCancel), FCancel);
      end);

 

I don't which of your methods is slow - `RunningStatistics` or `OnStatsRefresh` so I passed `FCancel` to both.

Share this post


Link to post

Thank you for your answer. So what you imply is that you cannot actually use TaskConfig(Parallel.TaskConfig.CancelWith(...)) on a TimedTask at all?

 

Edit: I'm asking because my problem isn't that the either of the internal method calls is actually very long and there is no way they would run longer than the provided timeout (unless there is a deadlock in my code that only happen when the task terminates). What I am seeing is that I seem to be unable to stop the timer at all from the inertnal code because the owner of that thread if never actually freed as far as I can tell (that is because of the way MVC framework works) so I need an external way to stop that process and a cancellation token seems like the right way to do it.

Edited by Fulgan

Share this post


Link to post
2 hours ago, Fulgan said:

So what you imply is that you cannot actually use TaskConfig(Parallel.TaskConfig.CancelWith(...)) on a TimedTask at all?

Sorry, I did not mean to imply that. You can definitely use TaskConfig.CancelWith and then check task.CancellationToken in your thread.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×