Fulgan 1 Posted January 24, 2020 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
Primož Gabrijelčič 223 Posted January 24, 2020 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
Fulgan 1 Posted January 27, 2020 (edited) 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 January 27, 2020 by Fulgan Share this post Link to post
Primož Gabrijelčič 223 Posted January 27, 2020 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