 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Mark Atkin Guest
|
Posted: Thu Apr 20, 2006 9:03 pm Post subject: Using TClientSocket in multi-threaded app |
|
|
I have a multi-threaded application where each thread uses TClientSocket to
communicate to a device on the network. I start a new thread for each
device that I need to talk to. My main form starts each of these threads,
and when a timer on the main form reaches 0, a flag is set in each thread to
tell the thead that it is time to talk to it's device. The next time the
thread checks it's status, the thread calls new TClientSocket to allocate a
new socket connection to use for the communication, retrieves the data, then
deletes it's instance of TClientSocket. Everything seems to work fine on my
computer. When I tried it on a client's computer, I began getting AVs when
the thread was calling new TClientSocket. I was creating my instances of
TClientSocket as follows:
TClientSocket *sock = new TClientSocket(MainForm);
where MainForm is the address of my form with the timer and the form that
creates the threads.
My theory as to why I would get AVs is that maybe all three threads are
calling new TClientSocket(MainForm) almost simultaneously and basically,
some method and/or property from my MainForm is being accessed by all three
threads to add the TClientSocket component to the ComponentList array and
increment the ComponentCount for the MainForm. I changed the socket
instantiation to new TClientSocket(NULL) and the problem has gone away.
This seems to agree with my theory, but it's just a theory. The biggest
hole in my theory that I can see is that it doesn't really explain why it
would work on my PC and not my clients. We are both running XPSP2 on P4s.
It still could be a timing issue, but I would like to prove this theory
somehow. Also, the only advantage that I can see to having MainForm being
the owner of the TClientSocket is that if something unexpected occurs and
the TClientSocket doesn't get deleted somehow, the MainForm will free up the
memory when the form gets destroyed. This advantage is greatly decreased by
the fact that the form is never destroyed until the program exits, in which
case Windows is going to free up the memory anyway.
Any thoughts, opinions, or additional theories (or even proofs with examples
) on this would be greatly appreciated.
Regards,
Mark Atkin |
|
| Back to top |
|
 |
SF Guest
|
Posted: Wed Apr 26, 2006 11:03 am Post subject: Re: Using TClientSocket in multi-threaded app |
|
|
| Quote: | TClientSocket *sock = new TClientSocket(MainForm);
|
I always use
TClientSocket *sock = new TClientSocket(NULL);
to create client sockets inside a thread. You yourself noticed
this is the right way.
| Quote: | My theory as to why I would get AVs is that maybe all three
threads are calling new TClientSocket(MainForm) almost
simultaneously and basically,
|
I don't care about that. Why should MainForm be the owner of an
object created inside a different thread?
| Quote: | The biggest hole in my theory that I can see is that it
doesn't really explain why it would work on my PC and not my
clients.
|
That should be deeply checked, but again, you shouldn't care too
much IMO.
| Quote: | It still could be a timing issue,
|
Or another thousands of issues...
| Quote: | Also, the only advantage that I can see to having MainForm
being the owner of the TClientSocket is that if something
unexpected occurs and the TClientSocket doesn't get deleted
somehow, the MainForm will free up the memory when the form
gets destroyed.
|
Not a big advantage. Almost a disadvantage under certain points
of view.
| Quote: | This advantage is greatly decreased by the fact that the form
is never destroyed until the program exits, in which case
Windows is going to free up the memory anyway.
|
Anyway, your thread should be strong enough to handle any
possible problem and free the TClientSocket pointer by itself.
Did you find anything more in the meantime?
HTH,
Stefano. |
|
| Back to top |
|
 |
Mark Atkin Guest
|
Posted: Wed Apr 26, 2006 6:03 pm Post subject: Re: Using TClientSocket in multi-threaded app |
|
|
"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:<444fab11$1 (AT) newsgroups (DOT) borland.com>...
| Quote: |
"Mark Atkin" <matkin (AT) windrock (DOT) com> wrote in message
news:4447ee51$1 (AT) newsgroups (DOT) borland.com...
The next time the thread checks it's status, the thread calls new
TClientSocket to allocate a new socket connection to use for
the communication, retrieves the data, then deletes it's instance
of TClientSocket.
A better approach would be to create the TClientSocket instance only once
when the thread is created and then free the TClientSocket when the thread
is being freed. You don't need to create a new TClientSocket instance
over
and over during the thread's lifetime. Just Connect/Disconnect it when
needed.
|
I have thought about doing this. I still might.
| Quote: | When I tried it on a client's computer, I began getting AVs when
the thread was calling new TClientSocket.
That is because of the way you are managing the TClientSocket. Keep
reading...
I was creating my instances of TClientSocket as follows:
TClientSocket *sock = new TClientSocket(MainForm);
That is not thread-safe. You are telling the TClientSocket to be owned by
a
TForm that resides in another thread. All of the ownership management
that
the VCL does internally only works when used in a single thread. In this
case, you should be using NULL instead to assign no owner to the
TClientSocket at all. The thread manages the TClientSocket's lifetime, so
there is no need to assign any owner anyway.
|
I don't know much about the internals of the VCL, but that was the only
conclusion I could come up with. I'm glad to know you came up with the same
conclusion.
| Quote: | My theory as to why I would get AVs is that maybe all three threads
are calling new TClientSocket(MainForm) almost simultaneously and
basically, some method and/or property from my MainForm is being
accessed by all three threads to add the TClientSocket component to
the ComponentList array and increment the ComponentCount for the
MainForm.
That is very likely, yes. Which is exactly why specifying an Owner is not
thread-safe at all.
|
Unfortunately for me, this is the first experience I've had with writing
multi-threaded applications. It's definitely been a learning experience.
| Quote: | I changed the socket instantiation to new TClientSocket(NULL) and
the problem has gone away.
There you go then.
The biggest hole in my theory that I can see is that it doesn't really
explain why it would work on my PC and not my clients.
A fluke, nothing more. It is likely just a timing issue, which are very
difficult to debug. Maybe your computer is slower then the client's
computer and thus the problem doesn't show up as much on your machine
since
the main thread properties/members are not access quite as simultaneously.
|
Everything always works fine on the development system, right? :P
| Quote: | Also, the only advantage that I can see to having MainForm being
the owner of the TClientSocket is that if something unexpected occurs
and the TClientSocket doesn't get deleted somehow, the MainForm
will free up the memory when the form gets destroyed.
That is a very bad design when threads are involved. You should not be
assigning ownership across threads. Each thread should own its own
objects.
If something goes bad and your main thread does not terminate the threads,
the threads will still be running when the main thread frees the objects
that the threads are using.
|
Again, I'm learning more all the time about using threads.
Thanks Gambit. |
|
| Back to top |
|
 |
Mark Atkin Guest
|
Posted: Wed Apr 26, 2006 6:03 pm Post subject: Re: Using TClientSocket in multi-threaded app |
|
|
"SF" <invalid (AT) NOSPAMinvalid (DOT) com> wrote in message
news:<444f4499$2 (AT) newsgroups (DOT) borland.com>...
| Quote: | TClientSocket *sock = new TClientSocket(MainForm);
I always use
TClientSocket *sock = new TClientSocket(NULL);
|
Me too, from now on ;)
| Quote: | to create client sockets inside a thread. You yourself noticed this is the
right way.
My theory as to why I would get AVs is that maybe all three threads are
calling new TClientSocket(MainForm) almost simultaneously and basically,
I don't care about that. Why should MainForm be the owner of an object
created inside a different thread?
|
When I first coded this, I didn't realize that NULL was a valid argument. I
thought I had to supply a valid TComponent instance. I now know that's not
the case.
| Quote: | The biggest hole in my theory that I can see is that it doesn't really
explain why it would work on my PC and not my clients.
That should be deeply checked, but again, you shouldn't care too much IMO.
|
I've got the same opinion, now. Who cares why it was working on my PC. It
probably shouldn't have been. I guess I was lucky that it failed so quickly
on my clients computer or this could have bitten me down the road.
| Quote: | It still could be a timing issue,
Or another thousands of issues...
Also, the only advantage that I can see to having MainForm being the
owner of the TClientSocket is that if something unexpected occurs and
the TClientSocket doesn't get deleted somehow, the MainForm will free up
the memory when the form gets destroyed.
Not a big advantage. Almost a disadvantage under certain points of view.
|
I see that, now.
| Quote: | This advantage is greatly decreased by the fact that the form is never
destroyed until the program exits, in which case Windows is going to
free up the memory anyway.
Anyway, your thread should be strong enough to handle any possible problem
and free the TClientSocket pointer by itself.
Did you find anything more in the meantime?
|
Not really. This definitely seems to have fixed my problem. It wouldn't
run more than 30 minutes before. Now, it has run for days with no problems.
Thanks Stefano. |
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Wed Apr 26, 2006 6:03 pm Post subject: Re: Using TClientSocket in multi-threaded app |
|
|
"Mark Atkin" <matkin (AT) windrock (DOT) com> wrote in message
news:4447ee51$1 (AT) newsgroups (DOT) borland.com...
| Quote: | The next time the thread checks it's status, the thread calls new
TClientSocket to allocate a new socket connection to use for
the communication, retrieves the data, then deletes it's instance
of TClientSocket.
|
A better approach would be to create the TClientSocket instance only once
when the thread is created and then free the TClientSocket when the thread
is being freed. You don't need to create a new TClientSocket instance over
and over during the thread's lifetime. Just Connect/Disconnect it when
needed.
| Quote: | When I tried it on a client's computer, I began getting AVs when
the thread was calling new TClientSocket.
|
That is because of the way you are managing the TClientSocket. Keep
reading...
| Quote: | I was creating my instances of TClientSocket as follows:
TClientSocket *sock = new TClientSocket(MainForm);
|
That is not thread-safe. You are telling the TClientSocket to be owned by a
TForm that resides in another thread. All of the ownership management that
the VCL does internally only works when used in a single thread. In this
case, you should be using NULL instead to assign no owner to the
TClientSocket at all. The thread manages the TClientSocket's lifetime, so
there is no need to assign any owner anyway.
| Quote: | My theory as to why I would get AVs is that maybe all three threads
are calling new TClientSocket(MainForm) almost simultaneously and
basically, some method and/or property from my MainForm is being
accessed by all three threads to add the TClientSocket component to
the ComponentList array and increment the ComponentCount for the
MainForm.
|
That is very likely, yes. Which is exactly why specifying an Owner is not
thread-safe at all.
| Quote: | I changed the socket instantiation to new TClientSocket(NULL) and
the problem has gone away.
|
There you go then.
| Quote: | The biggest hole in my theory that I can see is that it doesn't really
explain why it would work on my PC and not my clients.
|
A fluke, nothing more. It is likely just a timing issue, which are very
difficult to debug. Maybe your computer is slower then the client's
computer and thus the problem doesn't show up as much on your machine since
the main thread properties/members are not access quite as simultaneously.
| Quote: | Also, the only advantage that I can see to having MainForm being
the owner of the TClientSocket is that if something unexpected occurs
and the TClientSocket doesn't get deleted somehow, the MainForm
will free up the memory when the form gets destroyed.
|
That is a very bad design when threads are involved. You should not be
assigning ownership across threads. Each thread should own its own objects.
If something goes bad and your main thread does not terminate the threads,
the threads will still be running when the main thread frees the objects
that the threads are using.
Gambit |
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Wed Apr 26, 2006 10:03 pm Post subject: Re: Using TClientSocket in multi-threaded app |
|
|
"Mark Atkin" <matkin (AT) windrock (DOT) com> wrote in message
news:444faf4f$1 (AT) newsgroups (DOT) borland.com...
| Quote: | I don't know much about the internals of the VCL, but that was
the only conclusion I could come up with. I'm glad to know
you came up with the same conclusion.
|
I didn't "come up" with that conclusion. The behavior I described is a
known fact. Besides, I have the VCL source code, so it is just a matter of
looking up what the VCL actually does. Most of the VCL internals are NOT
thread-safe, so you have to be VERY careful when using the VCL with threads.
Gambit |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|