Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Indy 10 version of IdPeerThread.stop
#1
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
Reply
#2
(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.

Reply
#3
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
Reply
#4
(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.

Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)