Good afternoon
I'm in the process of updating an old delphi program to run on Delphi 10.4 - it uses an old version of Indy - thinking at least indy 8.
I have been able to find resources on most of the changes needed to be made to make it work with indy 10.
Except so far one.
IdPeerThread.Stop - I know IdPeerThread has been replaced with IdContext.
But I don't know what IdPeerThread.Stop does to know what procedure to IdContext replaced it with.
I have tried finding the source code, getting hold of indy 9 documentation hoping it would cover the changes.
Any tips?
Thanks,
Seth
(04-28-2022, 10:31 PM)dataspiller Wrote: [ -> ]IdPeerThread.Stop - I know IdPeerThread has been replaced with IdContext.
But I don't know what IdPeerThread.Stop does to know what procedure to IdContext replaced it with.
TIdPeerThread derives from
TIdThread, which derives from Delphi's native
TThread.
TIdThread.Stop() is just a wrapper to call
TThread.Terminate() or
TThread.Suspend(), depending on whether the thread is being pooled or not.
While
TIdThread itself still exists in Indy 10,
TIdPeerThread does not.
TIdTCPServer tasks have been decoupled from the threads that run them. There is no method to "stop" a
TIdContext. The preferred way is to simply disconnect the client that the
TIdContext is associated with, and let
TIdTCPServer stop the owning thread for you.
However, if you really need to, there is a way you can access the
TIdThread that is running a
TIdContext, and then you can
Stop() that thread. But only if
TIdTCPServer.Scheduler is set to a
TIdSchedulerOfThread-derived component (which it is by default,
TIdSchedulerOfThreadDefault.
TIdSchedulerOfThreadPool is also available):
Code:
uses
..., IdSchedulerOfThread;
TIdYarnOfThread(Context.Yarn).Thread.Stop();
That being said, the real question is - why are you trying to manually stop Indy's threads to begin with? You really shouldn't be doing that, even in earlier Indy versions. Can you show an example of your stopping code? There is likely a better way to handle whatever it is doing.
Thanks for the quick reply -
The procedure in question is:
Code:
procedure sendto_one (index : integer; line : string);
var List : Tlist;
begin
List := frm_server.skt_srv.Contexts.LockList;
try
try
TIdContext(List.Items[index]).Connection.IOHandler.WriteLn(Line);
except
TIdPeerThread(List.Items[index]).Stop;
end;
finally
frm_server.skt_srv.Contexts.UnlockList
end
end;
frm_server is a reference to a form, skt_srv is a TIdTCPServer dropped onto the form.
In the try section I already changed the TIdPeerThread to the TIdContext.
Based on context from when this procedure gets called. Looks like a list of clients are kept, then a string is being sent to a specific client - and if that fails, stop that client's connection.
Searching the entire project, it appears this is the only spot that an TIdPeerThread.Stop exists - based on a search of files in project for ").Stop;". I did find one .Free.
So based on your post - that would be replaced with "TIdYarnOfThread(TIdContext(List.Items[index]).Yarn).Thread.Stop();". - for direct update.
Addressing why it is being done this way, I don't know.
I'm taking code that I received 10+ years ago, trying to get it to compile and run now so that I can add a minor update to it for a person who still uses the application.
I'm not opposed to doing it the right way.
Seth
(04-29-2022, 01:07 AM)dataspiller Wrote: [ -> ]So based on your post - that would be replaced with "TIdYarnOfThread(TIdContext(List.Items[index]).Yarn).Thread.Stop();". - for direct update.
Yes.
However, that being said, this is pretty dangerous code in general.
You are not doing any bounds checking on indexing into the
Contexts list. There is a race condition where clients could connect/disconnect before you can lock the list, thus altering the index of the client you are intending to send to.
Also, you are keeping the list locked while sending. If the receiving client is dead/frozen, and its receiving buffer fills up, the send could freeze up, and then you would have a deadlock scenario that prevents other clients from connecting/disconnecting properly.
In general, I do not recommend sending unsolicited data directly to clients outside of the
OnExecute event, if you can help it. I typically recommend storing unsolicited data in a per-client thread-safe queue and letting the
OnExecute event send the queue when it is safe to do so, in between other reads/sends. This way, you don't have any conflicts with other data being sent by
OnExecute for command responses.
But, if
OnExecute doesn't send other data, then doing a direct send in this manner could work safely, if you are careful. And your protocol would have to be designed to support unsolicited data to begin with.
I certainly do not recommend terminating threads manually, though. In this case, I would probably just call
Disconnect()/
Binding.CloseSocket() on the failed client, and let the server cleanup the thread on its own time.