Recent

Author Topic: Sleep forever  (Read 4704 times)

jollytall

  • Sr. Member
  • ****
  • Posts: 353
Sleep forever
« on: November 27, 2023, 02:22:02 pm »
I have a main program that starts a number of threads and they do their own job and they never return (various server activities). As they are from various libraries, I cannot (and do not want to) make any of them the main program. The main program only waits forever and can actually be stopped in a controlled manner through system interrupts (what the main program handles correctly and stops the threads as well).
Now I have
Code: Pascal  [Select][+][-]
  1. while true
  2.   sleep(10000);
Actually I could put any high number in the sleep, does not matter, 10s just seems long enough not to use the CPU and still a "human" value.
Just for my taste it is still ugly. I would prefer an instruction like "Suspend".
(Yes, I could put my loop in a procedure called suspend, but it would still be the same.)
Isn't there any low level instruction that stops a thread (the main thread!) without exit?

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Sleep forever
« Reply #1 on: November 27, 2023, 02:27:05 pm »
When it is a GUI type of main application that starts your threads, you actually need to do nothing, beside starting threads and waiting (idle) for messages.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11919
  • FPC developer.
Re: Sleep forever
« Reply #2 on: November 27, 2023, 02:32:57 pm »
Note that not reacting to windows messages might bring up "DrWatson" "application is not responding, terminate?" messages.

jollytall

  • Sr. Member
  • ****
  • Posts: 353
Re: Sleep forever
« Reply #3 on: November 27, 2023, 06:40:24 pm »
Thanks, but it is not Windows GUI. This is a Linux Daemon.

dbannon

  • Hero Member
  • *****
  • Posts: 3156
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Sleep forever
« Reply #4 on: November 28, 2023, 06:32:32 am »
Hmm, not exactly what you are asking for but I do something like this -

Code: Pascal  [Select][+][-]
  1. var ExitNow : boolean = false;
  2. ....
  3. procedure SignalRec(sig : cint);cdecl;
  4. begin
  5.     writeln('----- Received SigTerm Signal, will exit shortly -----');
  6.     ExitNow := True;
  7. end;
  8.  
  9. .....
  10. Someloop begin
  11.             if ExitNow then begin                           // trigger by SIGTERM, default for kill command
  12.                 // do some tiding up
  13.                 terminate;                                
  14.                 exit;
  15.             end;
  16.             sleep(100);
  17. end;

In your case, you may not need do that tiding up but it does justify the endless loop.

Davo

Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

MarkMLl

  • Hero Member
  • *****
  • Posts: 7990
Re: Sleep forever
« Reply #5 on: November 28, 2023, 09:29:07 am »
In your case, you may not need do that tiding up but it does justify the endless loop.

Although that would still benefit from a sleep in the loop.

As a word of warning, I found myself in a position where I could benefit from signal handling to forcibly abort a background thread, but as the code began to get more complex it turned out to be more trouble than it was worth:

Code: Pascal  [Select][+][-]
  1. (* I was initially using                                                        *)
  2. (*                                                                              *)
  3. (*    PThread_kill(Handle, SIGHUP);      Anything stronger than HUP here        *)
  4. (*    WaitFor                            would affect the entire process.       *)
  5. (*                                                                              *)
  6. (* here, but the kill caused major problems in a program which was also hooking *)
  7. (* HUP and the WaitFor was just... well, it didn't work once I moved away from  *)
  8. (* using HUP for non-obvious reasons.                                           *)
  9.  

So from my POV, there's nothing wrong with making sure that syscalls always time out, then checking a termination flag.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Sleep forever
« Reply #6 on: November 28, 2023, 11:06:40 am »
Just for my taste it is still ugly. I would prefer an instruction like "Suspend".
In Windows there is SuspendThread which would solve the problem you've described, isn't there a "suspend thread" service/function in Linux you can use to accomplish the same ?
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

cdbc

  • Hero Member
  • *****
  • Posts: 1643
    • http://www.cdbc.dk
Re: Sleep forever
« Reply #7 on: November 28, 2023, 11:24:50 am »
Hi
Quote
isn't there a "suspend thread" service/function in Linux you can use to accomplish the same ?
Wouldn't it be possible to use an event?
IIRC TRTLEvent.Waitfor suspends the thread... (but then again I can't remember worth of sh*t)  :D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

jollytall

  • Sr. Member
  • ****
  • Posts: 353
Re: Sleep forever
« Reply #8 on: November 28, 2023, 11:25:45 am »
@dbannon
You actually made some meaning for the loop, but I think this is an even worse solution than the one I have. You use a 100ms Sleep (a sleep I wanted to avoid at the first place) and if the flag is set, within 100ms it is noticed and acted on in the main loop. It means that your process must be running every 100ms and You cannot make the sleep much longer, because then the signal is handled with a long delay. Not a big deal, to run the CPU for few clock cycles every 100ms, but if you do the tiding up directly in the SignalRec, then it is done immediately (not somewhere within the length of the sleep) and so the sleep can be much-much longer.

@MarkMLI
I don't really understand how your solution worked (and what was wrong in it).

@440bx
If I can trust SO, it is not implemented in Linux: https://stackoverflow.com/questions/11468333/linux-threads-suspend-resume
Also, IIRC in Windows that was for a thread other than the main program. I think the main program cannot stop itself.

In the meantime, I was also thinking another solution, but in this form, it does not work:
Code: Pascal  [Select][+][-]
  1. var
  2.   Access : TRTLCriticalSection;
  3. begin
  4. InitCriticalSection(Access);
  5. EnterCriticalSection(Access);
  6. EnterCriticalSection(Access);
  7. writeln('Finished');
  8. end.
  9.  
I thought that entering a critical section checks if that semaphore is already blocked, but apparently (as it is correctly written in the manual as well) it checks if that is already blocked BY ANOTHER thread. I probably still could use this trick, first entering a critical section in a sub-thread (and never leaving it) and then try to enter it in the main program as well. This would have the problem though that if for whatever reason the sub-thread is slow, the main program might get there first and exit. With some more checks I can still solve this.
Can it be a working and efficient solution?
« Last Edit: November 28, 2023, 11:39:32 am by jollytall »

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 859
Re: Sleep forever
« Reply #9 on: November 28, 2023, 11:26:45 am »
Two possible solutions. Simple one - use message loop. Thread is suspended, when it waits for next message. That's why GUI apps don't consume CPU time, when they're inactive. Even non-GUI application can create "invisible" window to process messages. As I know, Application.Handle - is exactly such invisible window. Console applications also have similar message loop.

A little bit harder solution - using sync objects and waiting for them to be released. Simple example: TThread.WaitFor.
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

jollytall

  • Sr. Member
  • ****
  • Posts: 353
Re: Sleep forever
« Reply #10 on: November 28, 2023, 11:43:50 am »
Wouldn't it be possible to use an event?

I tried two more tricks. None of them works, but I do not know why.
Code: Pascal  [Select][+][-]
  1. var
  2.   e : tEventObject;
  3. begin
  4. RTLEventWaitFor(RTLEventCreate);
  5. e:=tEventObject.Create(nil, false, true,'foo');
  6. e.WaitFor(INFINITE);
  7.  
The RTLEventWaitFor should be waiting forever, since noone sets that locally created event (noone can even know about it, as it is not even stored in a variable). Still it us on.
The second is similar, but there I cannot create the event object, it gives an error message.

cdbc

  • Hero Member
  • *****
  • Posts: 1643
    • http://www.cdbc.dk
Re: Sleep forever
« Reply #11 on: November 28, 2023, 12:10:07 pm »
Hi
I have an event-unit that can suspend your mainthread, BUT you can only wake it up from another thread....!
I dunno... Let me know if you wanna try  %)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

440bx

  • Hero Member
  • *****
  • Posts: 4727
Re: Sleep forever
« Reply #12 on: November 28, 2023, 01:19:16 pm »
Also, IIRC in Windows that was for a thread other than the main program. I think the main program cannot stop itself.
Just for "completeness", there really isn't anything special about the first thread in Windows which is usually thought of as the "main thread".  The only reason suspending that thread may cause problems is if that thread, as is usually the case, it the thread responsible for pumping messages.

IOW, it is possible and doable without any adverse side effects to suspend the "main program"'s thread without causing any problems provided the application is properly designed.

In yet other words, there is _nothing_ magical about the first thread started in Windows.  Windows does NOT care one way or the other _when_ a thread was created.  It does care about what it does, e.g, pump messages.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 859
Re: Sleep forever
« Reply #13 on: November 29, 2023, 07:58:06 am »
I usually use SyncObjs unit and classes like TCriticalSection and TEvent to sync my threads. Everything seems to work properly.
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

Thaddy

  • Hero Member
  • *****
  • Posts: 16132
  • Censorship about opinions does not belong here.
Re: Sleep forever
« Reply #14 on: November 29, 2023, 08:51:02 am »
The easy way is  to set/get the TThread.Suspended property, which is cross platform.
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018