0

I create a thread

type 
  ss_thread = class;

  ss_thread = class(TThread)
  protected
    Fff_id : string;
    Fff_cmd : string;
    Fff_host : string;
    Fff_port : TIdPort;
    procedure Execute; override;
  public
    constructor Create(const ff_id, ff_cmd: string; ff_host: string; ff_port: TIdPort);
  end;

constructor ss_thread.Create(const ff_id, ff_cmd: string; ff_host: string; ff_port: TIdPort);
begin
  inherited Create(False);
  Fff_id   := ff_id;
  Fff_cmd  := ff_cmd;
  Fff_host := ff_host;
  Fff_port := ff_port;
end;

...
id := 123; // dynamic
...

nst_ss_thread.Create(id, cmd, host, port);

and doing something on

procedure ss_thread.Execute;
var
  ws : TIdTCPClient;
  data : TIdBytes;
  i : integer;
  list : TList;
begin
      ws := TIdTCPClient.Create(nil);
      ws.Host := Fff_host;
      ws.Port := Fff_port;
....

I have master thread, which receive data from other source, and I need to forward all data to my threads with ID i received to 'ws' IdTCPClient.

How to have a list of IdTCPClients of all my created threads ?

Thanks

jmp
  • 2,456
  • 3
  • 30
  • 47

1 Answers1

1

Store them in a thread list.

ClientList: TThreadList<TIdTCPClient>;

Create one of these objects before you create any clients.

ClientList := TThreadList<TIdTCPClient>.Create;

Whenever you create a client, add it:

procedure ss_thread.Execute;
var
  List: TList<TIdTCPClient>;
....
ws := TIdTCPClient.Create(nil);
List := ClientList.LockList;
try
  List.Add(ws);
finally
  ClientList.UnlockList;
end;

Whenever you need to iterate over the clients, you can do so like this:

var
  List: TList<TIdTCPClient>;
  Client: TIdTCPClient;
....
List := ClientList.LockList;
try
  for Client in List do
    // do something with Client
finally
  ClientList.UnlockList;
end;

In the thread's destructor you will also need to remove the client from the list.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I was just about to suggest that too:) Beware of exceptions when adding/removing TIdTCPClients to/from the list and when sending - just about unavoidable at some stage due to the asynchronous states of the sockets. – Martin James Nov 27 '12 at 14:29
  • In thread's destructor (before `inherited` call) find it and remove from the `ClientList`. – TLama Nov 27 '12 at 14:30
  • You can cut down on the exceptions in some ways, eg. by forcing all threads to access the sockets/list through a CS-protected state machine, but I'm not sure it's worth it.. – Martin James Nov 27 '12 at 14:32
  • @TLama - yes, but that may be too late to prevent a sending thread from attempting to write to a dead socket and so generating an exception anyway:( – Martin James Nov 27 '12 at 14:34
  • @MartinJames The list is a thread list so I don't follow your point. Plus, this is Indy which uses synchronous sockets. The Indy people aren't keen on async sockets. – David Heffernan Nov 27 '12 at 14:36
  • @DavidHeffernan can you add a how to remove with inherited ? thanks – jmp Nov 27 '12 at 15:45
  • @waza123 The remove is the same as the add but instead of `List.Add(ws)` you write `List.Remove(ws)`. – David Heffernan Nov 27 '12 at 15:49
  • and how to pass 'ws' and 'id' variables into destructor Destroy; override; to search and remove? – jmp Nov 27 '12 at 16:44
  • Don't pass `ws` to the destructor. It's a local variable. Destroy it in the `Execute` method when you are done with it. Make sure you use try/finally. – David Heffernan Nov 27 '12 at 16:50
  • @DavidHeffernan - the client<>server synchronous sockets are 'asynchronous' because they are handled by serarate threads - I realized that what I had posted would be ambiguous just after I posted it:( Anyway, what I was referring to was the possibiity that a sender thread would attempt to write to a socket that was closed, but its thread had not quite got around to removing it from the list yet, (maybe list is blocked by the sender thread). – Martin James Nov 27 '12 at 20:17
  • 2
    @TLama: I would override the thread's `DoTerminate()` method, instead of using the destructor, to remove the `TIdTCPClient` from the list, as well as free the `TIdTCPClient`. – Remy Lebeau Nov 27 '12 at 21:46
  • like that ? procedure DoTerminate; override; procedure ss_thread.DoTerminate; begin nst_list.Remove(..); if Fff_ws <> nil then FreeAndNil(Fff_ws); inherited; end; – jmp Nov 27 '12 at 22:49
  • @waza123, yes, that way. Except that you don't need to check `if Fff_ws <> nil then` before calling `FreeAndNil`, just call `FreeAndNil(Fff_ws);`, the rest will do `FreeAndNil` for you. And just one sidenote. Try to use `T` at the beginning of any type name. It's an unwritten convention that everyone knows and somehow expects. So your thread class name would become `Tss_thread`. – TLama Nov 28 '12 at 02:53