Jump to content
dormky

How do I terminate a thread that doesn't have an Execute method ?

Recommended Posts

I have a thread that uses a timer to do work at fixed intervals and doesn't do anything except that. This means I have nothing to put in the Execute method ; but if I don't the thread never terminates. What am I supposed to do ?

Share this post


Link to post
16 minutes ago, dormky said:

I have a thread that uses a timer to do work at fixed intervals and doesn't do anything except that. This means I have nothing to put in the Execute method ;

The code within Execute method is what runs in the background thread. If you don't have any code there then you don't have a thread. If you want to run a timer in background thread, then you need to create that time in the Execute method , run a loop which handles messages and then release the times when thread terminates. There is plenty of code that needs to go in the Execute method. 

Quote

but if I don't the thread never terminates. What am I supposed to do ?

Background thread that is created by TThread class (at some point) will terminate when it exits the Execute method. Because there is nothing in the Execute method thread will terminate immediately when it runs. (since there is nothing there, it will  On the other hand, your thread object instance will be alive until you free it.

 

I cannot tell you more because you haven't shown any code you already have.

Edited by Dalija Prasnikar
  • Like 2

Share this post


Link to post

It feels so wasteful to have a method running with something like "while not Terminated do Sleep(10);". Is there not a better way of having the thread idle ?

Share this post


Link to post

You say you need it to wake up at fixed intervals. That is exactly what Sleep(..) is for.

Keep in mind that

  • 10 milliseconds is a very, very short interval. If we are talking about Windows, then accuracy that low is not guaranteed. As far as I know, it has been improved in recent Windows versions, but generally, you cannot rely on the thread waking up again in exactly 10 milliseconds
  • If you want the thread to wait for something else, you use an Event. You can have the thread wait for an event which is triggered from (for example) your main thread. See System.SyncObjs.pas for event classes.
  • Like 4

Share this post


Link to post
Just now, dormky said:

It feels so wasteful to have a method running with something like "while not Terminated do Sleep(10);". Is there not a better way of having the thread idle ?

If you want the timer to run in the thread then the thread will not idle. You need to run your timer related code within the Execute method. To simplify, the Execute method is the one that runs in the background thread, thread constructor does not run in the background thread. 

 

You have some deep misconceptions about how threads work, but I cannot help you if you don't show your code. Right now you are doing everything wrong and you are not running any code in the background thread.

  • Like 3

Share this post


Link to post

> You need to run your timer related code within the Execute method

 

I would need to have the timer callback set a flag that a loop in the Execute would check ? That seems exceedingly strange.

I just want a timer that exists and executes in a thread other then the main thread. The timer's interval is subject to change, and is in a class whose logic should be able to run on both main and other threads, hence why I haven't put the logic in the Execute method directly.

Share this post


Link to post

Well, it seems that no matter what I do, the timer's callback is always executed in the main thread. Anyone have a recommendation for a TTimer equivalent that has its callback executed in the thread it was created in ?

Share this post


Link to post

Into the Execute you need to have a code that will not exit till you need that thread alive.

procedure TMyThread.Execute;
var
  LHowMuchToWait: Integer;
  LDoExit: Boolean;
begin
  try
    repeat
      ExecuteMyClass(LHowMuchToWait, LDoExit);
      Sleep(LHowMuchToWait);
    until LDoExit or Terminated;
  finally
    Terminate;
  end;
end;

 

  • Like 1

Share this post


Link to post
1 minute ago, dormky said:

Anyone have a recommendation for a TTimer equivalent that has its callback executed in the thread it was created in ?

What is wrong with Sleep()

Share this post


Link to post
3 minutes ago, dormky said:

Anyone have a recommendation for a TTimer equivalent that has its callback executed in the thread it was created in ?

Did you read my post? If you don't like the Sleep(..), have the timer trigger an Event and have the thread wait for the event.

Share this post


Link to post
1 minute ago, Cristian Peța said:

What is wrong with Sleep()

Well, if someone's already made the relevant code to create a timer there's no reason to write one myself.

Share this post


Link to post

If you have a timer there is a possibility that your execution will not end and a new one will need to be started.

With Slepp() this can not happen.

Edited by Cristian Peța

Share this post


Link to post
1 minute ago, Der schöne Günther said:

Did you read my post? If you don't like the Sleep(..), have the timer trigger an Event and have the thread wait for the event.

Except that I'm putting the timer in a thread for a reason. If it's on the main thread, it runs the risk of getting delay by other work (namely, heavy drawing). If the timer is delayed, the event is delayed too.

Share this post


Link to post
1 minute ago, Cristian Peța said:

If you have a timer there is a possibility that your execution will not end and a new one will need to be started.

With Slepp() this can not happen.

That's not a problem here, the code called by the timer is "fire and forget".

Share this post


Link to post

You definitely have a misconception about how threads and timers work. Read the other answers and some documentation on the topic.

  • Like 2

Share this post


Link to post
2 minutes ago, dormky said:

That's not a problem here, the code called by the timer is "fire and forget".

It seems like you don't even need a timer in a background thread, you just want to periodically run some task in the background thread. 

 

procedure TForm2.Timer1OnTimer(Sender: TObject);
begin
  TTask.Run(
    procedure
    begin
      // call here anything that needs to run in the background thread
    end;
end;

 

Again, it would be so much easier to give you some suggestions if you would just show some of your code.

  • Like 1

Share this post


Link to post

 

4 minutes ago, dormky said:

the code called by the timer is "fire and forget"

 

15 minutes ago, dormky said:

If it's on the main thread, it runs the risk of getting delay by other work (namely, heavy drawing). If the timer is delayed, the event is delayed too.

Use Sleep() in the thread and start other threads at that interval.

The thread with the Sleep() will need to have highest priority.

Share this post


Link to post

There are many better alternatives to Sleep. 

https://learn.microsoft.com/en-us/windows/win32/sync/wait-functions#multiple-object-wait-functions

 

The downside of a single Sleep is that it blocks termination of the thread.

The downside of multiple Sleep + time checks to allow termination, consumes more CPU.

 

Signals, WaitForXXXX & Timeouts give you all the tools you need to have low cost and responsive threads - even if it requires a little more scaffolding code.

  • Like 2

Share this post


Link to post
56 minutes ago, Cristian Peța said:

What is wrong with Sleep()

You cannot terminate the thread while it's blocked by sleep.

+1 for SimpleEvent and Waitfor.

  • Like 3

Share this post


Link to post
1 minute ago, Lars Fosdal said:

The downside of multiple Sleep + time checks to allow termination, consumes more CPU.

You are right.

I'm using Sleep() only in Windows services in the ServiceExecute(). 50 or 100 ms is not an issues for a service to get down. And checking Terminated, an increment and loop every 50 ms is nothing.

Share this post


Link to post
10 minutes ago, Lars Fosdal said:

There are many better alternatives to Sleep. 

I don't think we are at that level yet. We first even have to establish what is even remotely appropriate solution, given that the problem is vague. And then we can start optimizing the code. So Sleep() suggestion is a valid one. If Sleep could be used, then we can offer better solutions than using Sleep().

Edited by Dalija Prasnikar
  • Like 1

Share this post


Link to post
1 hour ago, dormky said:

Except that I'm putting the timer in a thread for a reason. If it's on the main thread, it runs the risk of getting delay by other work (namely, heavy drawing). If the timer is delayed, the event is delayed too.

If the system is overloaded all activities and processes including threads, events, etc ... will inevitably be delayed.
To mitigate this you can just "play" with the thread priority.
Using sleep in a thread at a higher priority than normal is usually a satisfactory solution.
However, if the timer needs to be triggered (i.e. it is not always active), then you should use sleep in combination with a WaitFor.
As @Dalija Prasnikar says, it is not possible to provide you with further solutions if you do not present code or delve deeper into the topic.

Share this post


Link to post
1 hour ago, dormky said:

Except that I'm putting the timer in a thread for a reason. If it's on the main thread, it runs the risk of getting delay by other work (namely, heavy drawing). If the timer is delayed, the event is delayed too.

A thread using


 

While not terminated do
begin
    Dosomething;
    Sleep(xxx);
end;

 

 

is perfectly OK if the thread has to do something useful periodically and if xxx isn't a terribly small number.

 

But if "Dosomething()" is merely polling for some state change to respond to, then it's rather inefficient to have this thread constantly wakeup, consume CPU time and sleep again. 

The "Sleep(xxx)" also limits the response time and the number of state changes that can be handled per second.

 

For such a scenario it's much more efficient if you can wake up the thread "from the outside" ASAP when it has to react. This is where events really shine. 

 

 

Share this post


Link to post
1 hour ago, A.M. Hoornweg said:

[Sleep] is perfectly OK if the thread has to do something useful periodically and if xxx isn't a terribly small number.

I disagree. Sleep is only appropriate if the interval is very small and even then I wouldn't use it.

 

The problem is thread termination; If you are using Sleep then the thread cannot be terminated while Sleep is executing.

IMO the better solution, as have already been suggested, is to wait on an event with a timeout: If the event times out, do the task. If the event is signaled, terminate the thread. To terminate the thread, signal the event.

 

While waiting on an event is much more complicated than just calling sleep, if one is to use threads one might as well learn how to do these things. Threads are difficult and pretending they aren't will just lead to lessons learned, the hard way, later on.

  • Like 2

Share this post


Link to post
4 minutes ago, Anders Melander said:

While waiting on an event is much more complicated than just calling sleep, if one is to use threads one might as well learn how to do these things. Threads are difficult and pretending they aren't will just lead to lessons learned, the hard way, later on.

If you know absolutely nothing about threads, then Sleep can be a first step towards solution. It will at least give you a simple proof of concept code. If you need to learn everything at once it can be overwhelming.

 

But, again, at this point we are discussing the Sleep vs events while we don't even know if we are going in the right direction.

  • Like 4

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

×