Best practise to code inside a Listerner thread's Run method

Best practise to code inside a Listerner thread's Run method

Post by Gerhard Ve » Sat, 27 Aug 2005 03:16:08


What is the correct way to code the body of a listener thread's Run method.
This is of course a TIdThread.Run method. Here is a code snippet, which
version is better, if not any what would you guys suggest?

Version 1 is what I think but I would like if you guys can comment on the
code as well.

Version 1 - using an IF :
procedure TcsListenerThread.Run;
begin
inherited;
if (not Terminated) and (FProxyServer.FListener.Connected) then
begin
FRecievedData := FProxyServer.FListener.IOHandler.ReadLn(cCRLF2x);
if Terminated then Exit;
Synchronize(DataAvailable);
end;
end;

Version 2 - using a WHILE:
procedure TcsAsteriskListenerThread.Run;
begin
inherited;
while (not Terminated) and (FProxyServer.FListener.Connected) do
begin
FRecievedData := FProxyServer.FListener.IOHandler.ReadLn(cCRLF2x);
if Terminated then Exit;
Synchronize(DataAvailable);
end;
end;

Thanks
Gerhard.
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Martin Jam » Sat, 27 Aug 2005 03:40:17

> What is the correct way to code the body of a listener thread's Run
method.

First of all, 'listener thread' has a specific meaning in TCP serverland.
It's the thread that calls the 'listen' and 'accept' APIs and establishes
new TCP connections before handing them off to other threads for 'read'
calls etc. You should invent a new name for your proxy-read thread :)

What does it do, in the grand scheme of things? Does the dataAvailable
event have to be synchronised?

Rgds,
Martin

 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Team » Sat, 27 Aug 2005 03:53:19


Version 1 is the way to go since Run() is already called in a loop.
However, you do not need the first check of the Terminated property since
TIdThread already does that before calling Run(). Also, if your class
derives from TIdThread dirtectly then you do not need to call the inherited
Run(), which does nothing.

procedure TcsListenerThread.Run;
begin
if FProxyServer.FListener.Connected then
begin
FRecievedData :=
FProxyServer.FListener.IOHandler.ReadLn(cCRLF2x);
if not Terminated then Synchronize(DataAvailable);
end;
end;


Gambit
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Team » Sat, 27 Aug 2005 03:53:57


It does if the event handler is accessing the GUI.


Gambit
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Gerhard Ve » Sat, 27 Aug 2005 04:21:39

>> What does it do, in the grand scheme of things? Does

Well I thought about this one too. The DataAvailable method calls a method
on its owner which is the ProxyServer. I was not quite sure if I should use
Synchronize or not when it calls the method, was not sure if method calls
are queued.

Here is the code for the 2 methods:

procedure TcsListenerThread.DataAvailable;
begin
if not Terminated then
FProxyServer.PublishEvent(FRecievedData);
end;

procedure TcsProxyServer.PublishEvent(Event: String);
var
i : integer;
ClientList : TList;
Client : PClient;
begin
try
//obtain the list of clients connected
ClientList := Self.Contexts.LockList;

for i := 0 to ClientList.Count -1 do
begin
if TIdContext(ClientList[i]).Connection.Connected then
begin
//get the cleint record
Client := PClient(TIdContext(ClientList[i]).Data);
//only send event to this client if SendEvents is true
if Client.SendEvents then
TIdContext(ClientList[i]).Connection.IOHandler.Write(Event+cCRLF2x);
end;
end;
finally
Self.Contexts.UnlockList;
end;
end;
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Gerhard Ve » Sat, 27 Aug 2005 04:26:00

> Also, if your class
Correct but Delphi actually writes it for you when you press Shift,Ctrl
and C to create the methods in the implentation section. I also thought it
was good practise even thou it was do nothing;


Exellent thank you.

BTW I am still wrestling with the fact that the server hangs when I Set
Active to False when there are clients connected.

Gerhard
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Gerhard Ve » Sat, 27 Aug 2005 04:31:15

> First of all, 'listener thread' has a specific meaning in TCP serverland.
Yes I know. It is a thread using a TIdTCPClient connection that listen
to another server who pushes events to it. It then notify its owner the
proxy server which then pushes the events to all its clients who subsribed
for events. Alla Proxy Server.
Read the thread just few down "TIdTCPServer - Access thread in OnExecute -
in the last post I gave a bit of background.


See reply to Gambits post.

Thanks for the input guys - appreciated.
Gerhard
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Martin Jam » Sat, 27 Aug 2005 17:15:15


use

Method calls are just calls :) They are executed in the context of the
calling thread. There will be no queueing, or serialising, unless you add
some inter-thread signalling inside the method.


Since the LockList call protects the shared data and so serialises access by
signaling any other threads attempting to get in to block, this call would
seem to be safe to call from multiple threads. Whether it is efficient, or
whether some optimization might be made to the design, is another matter,
but, IMHO, you can call this fine from many peer threads without any
'synchronize'.

If I was doing this 'broadcast' type of thing, I would probably queue the
events to a 'send thread' that could perform the list iteration by itself.
This should reduce the amount of list-locking, since the send-thread may
find several events in it's input queue & could send them all at once, in
one iteration. This bechaviour could be 'encouraged' by lowering the
priority of the send thread.

Rgds,
Martin
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Gerhard Ve » Sun, 28 Aug 2005 02:20:43


I worked on a CORBA project about 4 years ago, and I vaguely remember
some problems we had with the CORBA implementation in Delphi6 regarding to
method calls being serialized. Cannot remember the exact issue have to look
in the project documents but anyway that is why I asked the question.

If the "send thread" could perform the iteration by itself it still has to
iterate through the clients connected correct which means it still has to
lock the list to prevent sending to clients that disconencted in the
meantime. Isn't that true? I cannot see how to do it otherwise but I am open
for suggestions.


I like the idea of sending maybe more than one event at once. I do have
another ProcessEventThread coded but is not using it at the moment. The
ListenerThread (yeah I know the name is confusing :) ) populates a buffer
and the ProcessEventsThread process the buffer but it still hands it over to
the ProxyServer to dish out the Events to its clients. The reason behind the
buffer was that I was afraid that some events will get lost while the
ProxyServer is stepping through its clients list publishing (if big number
of clients). But as I understand the TCP/IP socket implementation depends on
the platform, which allows 5 messages to be queued on Win2000 and XP but for
servers a maximum of 200 is allowed. Since I will most definitely deploy
this on a server platform the buffer thought took a back seat.

Regards
Gerhard
 
 
 

Best practise to code inside a Listerner thread's Run method

Post by Martin Jam » Sun, 28 Aug 2005 09:49:25


This is typical of what happens when you use hard-sync inter-thread comms
and 'freeOnTerminate' set false so that terminating threads have to be
waited for so they can be freed off by the 'owner' thread. This 'owner' is
often the main thread, so freezing the whole app.

Do you explicitly set Active to false during the app run, or is this
something that happens at app shutdown?

Rgds,
Martin