Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Jan : Re: AThreads and Thread manager..

www.cryer.info
Managed Newsgroup Archive

Re: AThreads and Thread manager..

Subject:Re: AThreads and Thread manager..
Posted by:"Remy Lebeau (TeamB)" (no.spam@no.spam.com)
Date:Fri, 5 Jan 2007 14:31:25

"Turboz" <turboz@turboz.moved.in> wrote in message
news:459ebbad@newsgroups.borland.com...

> I was accessing it through a CriticalSection so that only one thread
at a
> time could access the array..

Fair enough.  As long as there is some kin of locking mechanism in
place, then you can use whatever storage you want.

> Yes, all the threads go straight into a CriticalSection as soon as
the
> OnExecute event is fired. They then leave the CS when they are done
with
> their 'doings'.

You are not using a single critical section across multiple clients,
are you?  That is very inefficient.  Lock one client for writing data
and all clients are locked.  Each client should have its own critical
section, as I showed you earlier.

> Is it safe to write from one thread to another like that or should I
create a
> seperate thread (or use the main with timer) to do the writing?

You can write to a socket from multiple threads - as long as you are
serializing the writing so that the outbound packets do no overlap
(same thing with reading - you don't want one thread reading another
thread's data by accident).  A socket does not serialize the data for
you.  You have to do that yourself.

> my lack of understanding of the TThreadList

TThreadList is nothing more than a TList wrapped with a
TCriticalSection, and TList is nothing more than a dynamic array of
pointers.

> I thought a TThreadList had to have a connection to the server?

No.

> As mentioned before, I wanted to keep the offline users in the same
> place (array) aswell as the online users.

Which you can do quite easily if you use your own TThreadList (or any
other thread-safe container) to store the user info, as I demonstrated
earlier.

> Can I actually store offline client details in a TThreadList if they
do
> not have an active connection?

Yes.  TThreadList itself has nothing to do with connections at all.
It is a stand-alone thread-safe container of arbitrary pointers,
nothing else.  You are thinking too much about the TThreadList that
TIdTCPServer uses internally for tracking its client threads.  That is
completely separate.

> If so,  how?

I already showed you exactly how.

> Yes, as mentioned previously above, all my threads are entering a
> CriticalSection immediately. Whilst I didn't actually include that
in the
> code I posted yesterday (it was a simplifed version of my code) my
> code does make use a CS.

It sounds like it is using it very inefficiently, though.

> Yes, but if I store the offline users in my own list, I end up with
2 lists

So?  You don't have to do anything with the server's list.  Just focus
on your own list.  Leave the server alone to do its own thing.

> You see, this is where I'm getting confused. If the pointer can go
away
> at any time, then how can the AThread.Data object still be correctly
> assigned?

Because you get events from the server when the thread is
started/stopped, so you can keep the Data property updated
accordingly.  Also, by using those events to keep the user info
updated about which threads are available, you should never get into a
situation where you are trying to access an invalid thread.  If you
do, then you are not protecting yourself adequately enough.

> Surely if the AThread is dynamically reassinged, it would take the
.Data
> with it as it is a property of the AThread???

No, it would not.  Every time a new client connects to the server, it
is assigned to a TIdPeerThread instance, whether that be a new
instance, or an instance pulled from a pool.  Either way, the
TIdPeerThread is reset to a blank state before it actually begins
working with that client.  So no, the Data property is NOT preserved
from one client to the next.  That is why you have to use the
OnConnect/Disconnect events to keep everything updated as needed.

> Yes, but thats why I was using a dynamic array - each user has an
> indexed record.

Exactly.  All you have to do is associate that index with the
TIdPeerThread during the lifetime of the connection, and your code
will be able to directly find the user data for that client while it
is connected to the server.  That is where the TIPeerThread.Data
propety comes into play.  You also have a need to start with user data
can find the connection that belongs to it.  That is where the
TUser.Thread property comes into play.  You have to keep the two
properties in sync at all times.

> In reality, whats the difference between using a dynamic array to
> store users details and using a client object?

None whatsoever.  The only important thing is that you have a way of
getting from the thread to the user data, and vice versa.  What you
use to store the actual data, that is your choice.

> Yes, that was soemthing like I was trying to do - Associate a user
> with a thread pointer.

But that is only half the equation.  You have to do it both ways -
assign a thread to a user, and assign a user to a thread.  Then they
can find each other whenever needed

> Whilst admittedly also trying to identify the user from the thread
at the same time..

Which is the piece you have been missing so far.

> So, does the TUser object stay unique to each thread?

TUser is unique by itself.  When a specific client connects and logs
in, it has a specific TUser instance to describe it.  That TUser
instance stays in your list for as long as you need it.  While the
client is connected, that TUser is associated with the client's thread
as well.  When the client disconnects, the association is nullified,
but the TUser sticks around until you are done with it.

> EG if it's created in Thread1, then the TUser stays within THAT
thread
> and isn't accessed by all threads?... right?...

Only if you do not allow the same user to login with multiple
connections at a time.  Then yes, TUser will only be associated with 1
thread at a time.  Other threads can access the associated thread if
needed (for writing data).  But given a starting thread, only that
thread will have the TUser assigned to its Data property.

> As I understood it though, a TThreadlist was a property of the
> TIdTCPServer and could only be used for active connections??

TThreadList is a standalone class.  TIdTCPServer uses a TThreadList
instance for its own purposes, but TThreadList itself has nothing to
do with TIdTCPServer in general.  You can use it for whatever you
want.  It is a generic thread-safe container.

> So does each individual user need their own CS?

It may take up more resources, but it is more efficent in general.
There is no reason to block all clients just to access 1 specific
client.  If you do that, then you lose the benefits of threading.

> I was using one main CS declared as public in the main unit and
> then each thread was making a call to the CS to enter/leave - was
> I wrong to do this?

Although it will work, it is a major bottleneck in your code.  While
one client is working, all other clients are waiting for it to finish.
Then another client can begin its work while all the other clients
continue waiting, and so on.

> Ah... now this worries me, because above (at top of demo code) I
> made the assumption that the Client object stayed with the thread
> all the way until the client disconnected.

It does.

> Now it looks like I still have to find the client from the
AThread.Data
> each tiem I need to refer to it?

You have to do that anyway, if you only have a TIdPeerThread pointer
available to start with to look the user up with.  But there is
nothing stopping you from accessing the array directly whenever you
want (with proper locking, of course).

The whole point of using the Data property is to provide a one-to-one
link from a TIdPerThread pointer to the user data for that connection.
Nothing more.  If you have other ways of identifying and locating
users, then fine.  The Data property is there for convenience.  It is
not a requirement.

> If AThread can be dynamically reassigned at any time, then
> how will Client := TUser(AThread.Data); work?

The same TIdPeerThread instance that triggers the OnConnect event will
also trigger the OnDisconnect event.  So the value assigned to the
Data property inside the OnConnect event will still exist inside the
OnDisconnect event.  That is not what I was referring to about threads
going away and being reassigned.

> Could the procedure above be called internally from any thread?
> EG to send from user1 thread to user2 thread?

Yes.  That is the whole point of implementing a locking mechanism.  It
allows any thread to call the method at any time, and the integrity is
preserved.


Gambit

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive