TTimer stops after wake from sleep state lazarus / 34-Windows ---------------------------------------------------------------------- karloromic · 2019-09-16 11:56 Why TTimer stops after waking up from sleep state? I have a TTimer that runs every 5 seconds to check for network connectivity by creating thread every time (when thread starts TTimer is disabled) and TTimer is reenabled on thread finished. Windows 10 x64 Lazarus x32 2.0.4 ---------------------------------------------------------------------- rvk · 2019-09-16 13:17 I'm not sure about your TTimer problem (it's probably not re- enabled)... but why are you using a TTimer in this case? Isn't it easier to just use the thread and do the check in a loop with 5 seconds sleep. ---------------------------------------------------------------------- karloromic · 2019-09-16 13:37 Quote from: rvk on September 16, 2019, 03:17:19 pmI'm not sure about your TTimer problem (it's probably not re-enabled)... Yeah i figured it out by testing other timer which is enabled all the time (works fine after wake). Quote from: rvk on September 16, 2019, 03:17:19 pmwhy are you using a TTimer in this case? Isn't it easier to just use the thread and do the check in a loop with 5 seconds sleep. Yes it would be easier, what would be the best way to create that loop, simplest as posible? Something like this? repeat DoSomethingHere(x); x := x + 1; sleep(5000); until x = 10; but i need it running indefinitely ---------------------------------------------------------------------- rvk · 2019-09-16 13:40 Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TMyThread.Execute;begin while not Terminated { and MaybeSomeOtherConditionIfNeeded } do begin // DoYourCheck Sleep(5000); end;end; Terminating the thread will set Terminated to true so the loop will end (during your TThread.WaitFor). ---------------------------------------------------------------------- karloromic · 2019-09-16 13:43 Quote from: rvk on September 16, 2019, 03:40:51 pmCode: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TMyThread.Execute;begin while not Terminated { and MaybeSomeOtherConditionIfNeeded } do begin // DoYourCheck Sleep(5000); end;end; Terminating the thread will set Terminated to true so the loop will end (during your TThread.WaitFor). Wouldn't Execute method run only once and then stop/terminate? ---------------------------------------------------------------------- rvk · 2019-09-16 13:45 Quote from: karloromic on September 16, 2019, 03:43:56 pmWouldn't Execute method run only once and then stop/terminate? Not if you put a while-loop in there That's the 'normal' place to do it in a thread. See the examples on this page: https://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial ---------------------------------------------------------------------- karloromic · 2019-09-16 13:49 Quote from: rvk on September 16, 2019, 03:45:30 pmQuote from: karloromic on September 16, 2019, 03:43:56 pmWouldn't Execute method run only once and then stop/terminate? Not if you put a while-loop in there That's the 'normal' place to do it in a thread. See the examples on this page: https://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial Sorry, didnt see while there, my mistake Thank you very much! ---------------------------------------------------------------------- Thaddy · 2019-09-16 15:01 stop and start do also magic.... ---------------------------------------------------------------------- rvk · 2019-09-16 15:09 Quote from: Thaddy on September 16, 2019, 05:01:48 pmstop and start do also magic.... TThread.Stop ???? Does that one really exist? ---------------------------------------------------------------------- karloromic · 2019-09-16 18:59 Quote from: rvk on September 16, 2019, 05:09:00 pmQuote from: Thaddy on September 16, 2019, 05:01:48 pmstop and start do also magic.... TThread.Stop ???? Does that one really exist? Looking through documentation and source code, it doesn't. ---------------------------------------------------------------------- ASerge · 2019-09-16 20:33 Quote from: karloromic on September 16, 2019, 01:56:42 pmWhy TTimer stops after waking up from sleep state? Project with one TTimer and code Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Timer1Timer(Sender: TObject);begin Caption := TimeToStr(Time);end;shows the time and after sleep. ---------------------------------------------------------------------- rvk · 2019-09-16 21:17 Quote from: ASerge on September 16, 2019, 10:33:46 pmQuote from: karloromic on September 16, 2019, 01:56:42 pmWhy TTimer stops after waking up from sleep state? Project with one TTimer and code Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Timer1Timer(Sender: TObject);begin Caption := TimeToStr(Time);end;shows the time and after sleep. The problem probably lies in the fact that the ttimer is disabled when the thread is started and enabled again when the thread ends. So the problem is not in the ttimer but in the detection of the end of the thread. And without any sample code it's hard to find out what. ---------------------------------------------------------------------- winni · 2019-09-16 21:49 @karloromic: I think you make yourself things complicated. The timer wakes up all n milliseconds - 5000 in your case. You don't need to start a thread to detect your network connection. Just place the code inside the procedure Timer1Timer. Then you have all that you need. If you insist on using a thread then set on creating the thread Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i FreeOnTerminate := True; Then you don't have to free the thread when he is finished. That's all. Winni ---------------------------------------------------------------------- karloromic · 2019-09-16 22:19 Quote from: winni on September 16, 2019, 11:49:06 pm@karloromic: I think you make yourself things complicated. The timer wakes up all n milliseconds - 5000 in your case. You don't need to start a thread to detect your network connection. Just place the code inside the procedure Timer1Timer. Then you have all that you need. If you insist on using a thread then set on creating the thread Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i FreeOnTerminate := True; Then you don't have to free the thread when he is finished. That's all. Winni If i place the code inside procedure OnTimer then the application freezes until connection is made and all checks return result, that can take up to 10 seconds depending on connection speed and latency, and for all that time my program would be frozen. Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //set on creating the threadFreeOnTerminate := True;I did. TTimer works fine as stated by ASerge and also tested by me the same way. The problem is in my code. My source code is too big to be pasted here but i can explain. - TTimer is created and its interval value is 5000 and is enabled on form create Repeating this - OnTimer disables itself and starts new Thread(CreateSuspended) - Thread.OnCreate calls inherited Create(CreateSuspended) and sets FreeOnTerminate := True; - OnTimer Starts the thread - Thread execute internet check code and on the end of Execute updates data to form with Synchronize(@UpdateStatus); - UpdateStatus method updates data and when finished updating data, enables TTimer again End Repeat You can imagine Sleep and Wake event in any time of this code ---------------------------------------------------------------------- winni · 2019-09-16 22:54 @karloromic: Okay, I think you like this complicated stuff. But the problem is at only one point: If you do a synchronous call to the net you will always have a problem if you wait for connection. And the UI freezes. So the one solution is to do an asynchronous call to the net in a loop until you get a connection. Or you make a synchrous call with a short timeout until you get a connection. Or give up. I use for checking this simple function made with the help of netdb and Sockets - two FPC units: Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function HostByName (const who : string; var IP : String): Boolean; inline;Var H : THostEntry; begin result := ResolveHostByName(who,H); if result then IP := HostAddrToStr(H.Addr) else IP := ''; end; So you can call for something that is always up: Google or Amazon, so that they this time do something useful. Perhaps you can even adjust the timeout. Winni ---------------------------------------------------------------------- karloromic · 2019-09-17 00:25 @winni The way i do it is inside Thread.Execute i check internet in two phases: Ping timeout := 2000ms 1. Ping 8.8.8.8. / if no response in 2000ms then ----Google DNS Ping 8.8.4.4. / if no response -||- ----Google DNS Ping 1.1.1.1. ---Cloudfare Only if phase 1 was unsuccesfull do phase 2 ConnectionTimeout := 2000 IOTimeout := 3000 2. Send HTTP header request and check responsecode and headers https://google.com. / If not statuscode 200 OK then https://bing.com / -||- https://yahoo.com / -||- ..... If those 2 phases all return false then Internet connection state is offline I do the second phase because: "Some software firewalls, as well as NAT routers may block ping requests in an effort to "hide" your external IP address and prevent any response to potential intruders and prevent possible denial-of- service attacks in the form of a ping flood, in which an attacker overwhelms the victim with ICMP echo request packets." - source https://www.speedguide.net/faq/how-to-become-pingable-behind-a- routerfirewall-376 ---------------------------------------------------------------------- winni · 2019-09-17 16:22 @karloromic You gave enough arguments not to use ping. Additional is to say that some routers have an option in the interface with the caption "transmit ping" an with one click you can disable it. And the next point is, that ping by default runs with low priority. And if there is a hell of traffic on a router, it is allowed to drop the ping. So you never know if you can rely on your information if the net is up or down. If you want a more reliable answer, ask your nameserver for a well known address like I showed in my example. Winni ---------------------------------------------------------------------- karloromic · 2019-09-17 16:27 Quote from: winni on September 17, 2019, 06:22:06 pm@karloromic You gave enough arguments not to use ping. Additional is to say that some routers have an option in the interface with the caption "transmit ping" an with one click you can disable it. And the next point is, that ping by default runs with low priority. And if there is a hell of traffic on a router, it is allowed to drop the ping. So you never know if you can rely on your information if the net is up or down. If you want a more reliable answer, ask your nameserver for a well known address like I showed in my example. Winni What is possible hang time and doest timeout exists when you ask nameserver for wellknown address? Also what about DNS caching, would that create a problem? ---------------------------------------------------------------------- ASerge · 2019-09-17 16:58 Quote from: karloromic on September 17, 2019, 12:19:30 amRepeating this - OnTimer disables itself and starts new Thread(CreateSuspended) - Thread.OnCreate calls inherited Create(CreateSuspended) and sets FreeOnTerminate := True; - OnTimer Starts the thread - Thread execute internet check code and on the end of Execute updates data to form with Synchronize(@UpdateStatus); - UpdateStatus method updates data and when finished updating data, enables TTimer again End Repeat Perhaps the UpdateStatus or TThread.Execute code is not reentrant? For example. - UpdateStatus method updates data and when finished updating data, enables TTimer again Computer falls asleep Computer wakes up (timer interval has expired) - OnTimer Starts the thread Two threads exists. @rvk has already written about a better solution. BTW: TThread.OnTerminate is called after the Execute method and before releasing the thread, and in the context of the main thread. There is no need for an additional UpdateStatus method. ---------------------------------------------------------------------- karloromic · 2019-09-17 17:16 Quote from: ASerge on September 17, 2019, 06:58:52 pm] Perhaps the UpdateStatus or TThread.Execute code is not reentrant? For example. - UpdateStatus method updates data and when finished updating data, enables TTimer again Computer falls asleep Computer wakes up (timer interval has expired) - OnTimer Starts the thread Two threads exists. @rvk has already written about a better solution. BTW: TThread.OnTerminate is called after the Execute method and before releasing the thread, and in the context of the main thread. There is no need for an additional UpdateStatus method. Yes, its possible. Yes, i'm going to use while not Terminated loop as suggested by @rvk as its much more simple and cleaner approach, no need to create thread every 5 seconds. Then i dont need UpdateStatus method at all, as OnTerminate does the same thing. Thank you ---------------------------------------------------------------------- winni · 2019-09-17 18:35 @karloromic Good that you simplified your code. From memory I say, that the reply time for an unknown internet address was a maximum of 3 seconds but in average 2 seconds. And the timeout for no connection to the DNS server is less than two seconds. What kind of DNS Cache do you mean? If you have a DNS Cache in your LAN you must pass it by. If you mean the DNS Cache of your provider, you don't have to care, because yout got a WLAN connection anyway. Winni ---------------------------------------------------------------------- karloromic · 2019-09-17 19:25 Quote from: winni on September 17, 2019, 08:35:19 pm@karloromic Good that you simplified your code. From memory I say, that the reply time for an unknown internet address was a maximum of 3 seconds but in average 2 seconds. And the timeout for no connection to the DNS server is less than two seconds. What kind of DNS Cache do you mean? If you have a DNS Cache in your LAN you must pass it by. If you mean the DNS Cache of your provider, you don't have to care, because yout got a WLAN connection anyway. Winni What packages and unit are required for ResolveHostByName and where can i get them? ---------------------------------------------------------------------- winni · 2019-09-17 19:45 Hi! Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses .....,netdb, Sockets; Both units are in the fpc-sources, fpcsrc/3.0.4/packages/fcl-net so you have nothing to install. You don't have to install any package. Winni ---------------------------------------------------------------------- karloromic · 2019-09-17 19:50 Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, netdb, Sockets; type TForm1 = class(TForm) private public function HostByName (const who : string; var IP : String): Boolean; inline; end; var Form1: TForm1; implementation {$R *.lfm} function HostByName (const who : string; var IP : String): Boolean; inline;Var H : THostEntry; begin result := ResolveHostByName(who,H); if result then IP := HostAddrToStr(H.Addr) else IP := ''; end; end. I get: unit1.pas(8,58) Fatal: Cannot find netdb used by Unit1 of the Project Inspector. ---------------------------------------------------------------------- winni · 2019-09-17 20:08 Do you have the fpc sources installed? That is necessary! ---------------------------------------------------------------------- karloromic · 2019-09-17 20:20 Quote from: winni on September 17, 2019, 10:08:14 pmDo you have the fpc sources installed? That is necessary! Do i? (Attachment) ---------------------------------------------------------------------- winni · 2019-09-17 20:41 Strange, strange, strange ..... We work around: Place your cursor on "uses ......, netdb,.....; Press Alt CursorUp Now the unit netdb should appear in an editor tab.Place your cursor in this unit. Press Shift F11 He asks if he should add the unit to the project. YES. Save everything: Ctrl Shift S That should help. ---------------------------------------------------------------------- karloromic · 2019-09-17 20:50 @winni It solved the problem, however another one surfaced.. ---------------------------------------------------------------------- winni · 2019-09-17 22:09 Oops - you are using Windows, as I saw from the screenshots. Sorry - netdb .is Linux only. Then use another way with the fphttpclient , which can be also used in Windows. There is a good page in the wiki: https://wiki.lazarus.freepascal.org/fphttpclient At the end of the page is a Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetExternalIPAddress: string; Change it to your needs. This can be used for checking if an internet connections is possible. Winni ---------------------------------------------------------------------- winni · 2019-09-17 23:32 @karloromic Made a little demo program with the routine from the wiki page. Runs well with Linux and should also do with Windows. The timer interval is set to 1 second because the reactions are very quick. Test it! Zip file attached. Winni ---------------------------------------------------------------------- karloromic · 2019-09-18 06:46 Quote from: winni on September 18, 2019, 01:32:31 am@karloromic Made a little demo program with the routine from the wiki page. Runs well with Linux and should also do with Windows. The timer interval is set to 1 second because the reactions are very quick. Test it! Zip file attached. Winni Wow, thanks, i will test it out now ---------------------------------------------------------------------- karloromic · 2019-09-18 07:32 @winni Code: Pascal [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit NetAlive1; {$mode objfpc}{$H+} // Winni Bartnick, 18.9.2019 interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls; type { TForm1 } TForm1 = class(TForm) Button1: TButton; Label1: TLabel; Label2: TLabel; Timer1: TTimer; procedure Button1Click(Sender: TObject); procedure GetMyIPAddress; procedure Timer1Timer(Sender: TObject); private public end; var Form1: TForm1; implementation uses fphttpclient, RegexPr; {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);begin Close;end; // stolen fom https://wiki.lazarus.freepascal.org/fphttpclient// modifiedprocedure TForm1.GetMyIPAddress;var HTTPClient: TFPHTTPClient; IPRegex: TRegExpr; RawData: string; msg: string;begin try HTTPClient := TFPHTTPClient.Create(nil); IPRegex := TRegExpr.Create; try //returns something like: {