Recent

Author Topic: Killing off stucked thread  (Read 9120 times)

TCH

  • Full Member
  • ***
  • Posts: 200
Killing off stucked thread
« on: October 01, 2017, 11:04:40 pm »
I have a thread with a HTTP GET request inside. The problem is, when the request does not returns (i had set IOTimeout to 3000 for TFPHttpClient, but no avail, it does not returns after 3 seconds), the thread stucks. Even if i set the Terminated property to true, it does no good, since the thread never gets to that part when it can exit if it's terminated. (Or maybe it does, but only after a lot of time...)

The question is: how can i kill this stucked thread safely? Without causing crashes or freezes.

Or maybe i'm doing wrong the timeout setting? I just have to set the IOTimeout to 3000 for 3 seconds, or aren't i?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Killing off stucked thread
« Reply #1 on: October 01, 2017, 11:18:25 pm »
Killing threads is never safe. Usually you can get away with it, but it leaks memory and risks deadlocks.

The best thing you could try to do is to force some error on the socket handle (by calling some socket function on it), and hope it gets out whatever it is stuck in and honors TERMINATED.

Such tricks, like killing threads however, are not very portable, since it depends on implementation details.

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Killing off stucked thread
« Reply #2 on: October 01, 2017, 11:22:41 pm »
I see, thanks. Well, this rarely happens and there is no allocated memory or opened files in the thread, when the GET stucks, so if there is no crash, then it's okay.

How can i call a socket function on a local TFPHttpClient from a different thread? Because if it snaps out from the GET, then it does not need to be terminated at all.

Any idea, why TFPHttpClient ignores IOTimeout?
« Last Edit: October 01, 2017, 11:35:43 pm by TCH »

balazsszekely

  • Guest
Re: Killing off stucked thread
« Reply #3 on: October 02, 2017, 06:34:08 am »
Quote
Any idea, why TFPHttpClient ignores IOTimeout?
IOTimeout is a connection timeout, it won't help if the server is online, but busy with something else(slow maybe). However there is a solution, in the latest versions of fpc(3.1.1 +) there is a Terminate method which will force FPHttpClient to abort immediately after the current chunk is received/send. If switching to FPC trunk is not an option for you, just extract the attached fphttpclient.pp unit to your project folder and you're good to go. Please do the following:
1. Measure your own time
2. After a predefined number of seconds, just call FPHttpClient.Terminate

PS: I tested this method extensively in my applications and it works well.


TCH

  • Full Member
  • ***
  • Posts: 200
Re: Killing off stucked thread
« Reply #4 on: October 02, 2017, 12:38:14 pm »
Thanks for the tip, but still, how could i call FPHttpClient.Terminate on a locally declared FPHttpClient? Maybe i should pass it's pointer to a global variable and handle it from a TTimer? Can i do that?

balazsszekely

  • Guest
Re: Killing off stucked thread
« Reply #5 on: October 02, 2017, 01:25:18 pm »
Quote
how could i call FPHttpClient.Terminate on a locally declared FPHttpClient?
What do you mean by "locally declared FPHttpClient"? In you original post you said: "I have a thread with a HTTP GET request inside". I assume FPHttpClient is declared inside the private section of the thread. Now all you have to do is declare a public variable like NeedToTerminate. On the setter just call FPHttpClient.Terminate, this way the HTTP GET request will exit immediately, causing the thread to terminate, unless you have something else inside the execute method of course.  So basically:
1. Create/start the thread
2. Start a timer
3. When the timer ticks, just set YourThread.NeedToBreak to true

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Killing off stucked thread
« Reply #6 on: October 02, 2017, 01:54:07 pm »
Quote
how could i call FPHttpClient.Terminate on a locally declared FPHttpClient?
What do you mean by "locally declared FPHttpClient"? In you original post you said: "I have a thread with a HTTP GET request inside". I assume FPHttpClient is declared inside the private section of the thread.
Nope, sorry, i was misunderstandable. The FPHttpClient is declared inside a separate function which is not a part of the thread, but it is available in the entire unit and the thread calls this function.

Also, does FPC 3.1.1 work under OSX 10.6?

balazsszekely

  • Guest
Re: Killing off stucked thread
« Reply #7 on: October 02, 2017, 02:17:23 pm »
Quote
Nope, sorry, i was misunderstandable. The FPHttpClient is declared inside a separate function which is not a part of the thread, but it is available in the entire unit and the thread calls this function.
Well you can change that if you like. If the function is called only from the thread, there is no point to declare it as a separate function. Since I know nothing about the internal structure of your program, I cannot give you more useful advice. I'm just shooting in the dark.

Quote
Also, does FPC 3.1.1 work under OSX 10.6?
I see no reason why FPHttpClient.pp shouldn't work on OSX 10.6. Just give it a quick try.

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Killing off stucked thread
« Reply #8 on: October 02, 2017, 03:21:25 pm »
Quote
Nope, sorry, i was misunderstandable. The FPHttpClient is declared inside a separate function which is not a part of the thread, but it is available in the entire unit and the thread calls this function.
Well you can change that if you like. If the function is called only from the thread, there is no point to declare it as a separate function. Since I know nothing about the internal structure of your program, I cannot give you more useful advice. I'm just shooting in the dark.
No, actually you are correct. The function was initially used by several other parts, but when i made the image loading threaded, then all other usage were removed. Thanks for pointing out. I think that will be the solution.
Quote
Also, does FPC 3.1.1 work under OSX 10.6?
I see no reason why FPHttpClient.pp shouldn't work on OSX 10.6. Just give it a quick try.
Good. I'll try it under OSX 10.4 too, maybe i'll have luck. Actually i use the Synapse extension under OSX 10.4 and FPHttpClient under the rest of the OS-es, because OSX 10.4 does not have FPC 3, but maybe the FPHttpClient from 3.1 will work under OSX 10.4 too. If it does not work, then it means, that under OSX 10.4 the stuck is unsolvable. Or only available via killing the thread itself.

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Killing off stucked thread
« Reply #9 on: October 23, 2017, 03:47:19 pm »
Unfortunately, this method seems to be not working.

I have put the fphttpclient.pp 3.1.1 to my project dir. I have put the FPHTTPClient declaration into the public part of the thread. I made a FPHTTPClient.Get to an unreachable IP address, then i called the FPHTTPClient.Terminate from the main thread. No avail. It stucked.

balazsszekely

  • Guest
Re: Killing off stucked thread
« Reply #10 on: October 23, 2017, 04:39:58 pm »
@TCH
Can you attach a test project which demonstrates the issue?
You can also check OPM, the same method is used there and it works fine.

TCH

  • Full Member
  • ***
  • Posts: 200
Re: Killing off stucked thread
« Reply #11 on: October 24, 2017, 02:01:23 pm »
Yes, i attached a test program which demonstrates my problem. I hope i've done it wrong, elseway i don't have any solution as it turned out, that if the FPHTTPClient stucks inside the thread, then i cannot kill the thread by calling Free(). If i do, the thread (main or sub) calling the Free() method will freeze too.

Of course i can wait until the client will stop the get method by itself, but then the program will have to wait for ~120 seconds...

Code: Pascal  [Select][+][-]
  1. program kill_fphttpclient;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses cthreads, Classes, fphttpclient, SysUtils;
  6.  
  7. type
  8. TTestThread = class(TThread)
  9.         protected
  10.                 procedure Execute; override;
  11.         public
  12.                 constructor Create(CreateSuspended: boolean);
  13.                 var client: TFPHTTPClient;
  14.                 var response: string;
  15. end;
  16.  
  17. constructor TTestThread.Create(CreateSuspended : boolean);
  18. begin
  19.         inherited Create(CreateSuspended);
  20.         Self.client := nil;
  21. end;
  22.  
  23. procedure TTestThread.Execute;
  24. begin
  25.         Self.client := TFPHttpClient.Create(nil);
  26.         Self.response := client.Get('http://185.80.48.255/?check');
  27.         client.Free;
  28.         client := nil;
  29. end;
  30.  
  31. var
  32.         thr: TTestThread;
  33.         i: integer;
  34.  
  35. begin
  36.         thr := TTestThread.Create(false);
  37.         i := 0;
  38.         repeat
  39.                 sleep(10);
  40.                 inc(i);
  41.         until (thr.Finished) or (i >= 500);
  42.         if (i >= 500) then
  43.         begin
  44.                 writeln('Timeout.');
  45.         end
  46.         else
  47.         begin
  48.                 writeln('Response: ' + thr.response);
  49.         end;
  50.         if (not thr.Finished) then
  51.         begin
  52.                 if (thr.client <> nil) then
  53.                 begin
  54.                         thr.client.Terminate;
  55.                 end;
  56.                 repeat
  57.                         sleep(10);
  58.                 until thr.Finished;
  59.         end;
  60.         thr.Free;
  61. end.
  62.  

(OFF: Why on earth i cannot attach a PAS file?)

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Killing off stucked thread
« Reply #12 on: October 24, 2017, 03:37:07 pm »
(OFF: Why on earth i cannot attach a PAS file?)
Because .pas or pp files are not registered as a MIME type on the server. Simply sloppy forum maintenance. I don't get that too.<grumpy mode  >:D >:D>
Usually, if it the example is not too long, simply open up a code block.

For maintainers: make pas and pp etc alias for txt.
« Last Edit: October 24, 2017, 03:41:03 pm by Thaddy »
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6112
Re: Killing off stucked thread
« Reply #13 on: October 24, 2017, 04:10:41 pm »
in the latest versions of fpc(3.1.1 +) there is a Terminate method which will force FPHttpClient to abort immediately after the current chunk is received/send.
If Terminate only works after a current chunk is send or received it won't do anything for the timeout of the connection. During the connection there are no chunks of data send or received  :(

For this to work fpconnect should be put in non-blocking mode and then you can use select() with a different timeout to measure when the connection is established.

Another option would be to ping the server before making contact to know if it's online.
« Last Edit: October 24, 2017, 04:18:28 pm by rvk »

balazsszekely

  • Guest
Re: Killing off stucked thread
« Reply #14 on: October 24, 2017, 10:14:08 pm »
@rvk
Quote
If Terminate only works after a current chunk is send or received it won't do anything for the timeout of the connection. During the connection there are no chunks of data send or received  :(
True, but for connection timeout you can set the FPHttpClient.IOTimeout(ms), which internally calls fpsetsockopt. According to the documentation this should work even with blocking socket...and it does on linux, but fails on windows. Probably some params are not passed correctly or is a windows bug.

 

TinyPortal © 2005-2018