🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.delphi.nativeapi.win32
19 messages
19 total messages Started by Enquiring Mind Sat, 12 Jul 2008 17:02
How to dispatch an event handler in a thread-safe way
#179
Author: Enquiring Mind
Date: Sat, 12 Jul 2008 17:02
39 lines
2900 bytes
Hi,

I have an object class which is designed to be used concurrently by multiple 
threads. It owns a critical section which threads can use to acquire 
exclusive access to the object before calling one of the object's methods. 
The class also exposes an event intended to be used to hold an event handler 
that updates the user interface.

The problem is how to dispatch the event handler in a thread-safe way. The 
obvious solution is to call the  TThread class method Synchronize, but 
because my class is not a thread class descendent, it does not have a thread 
object that it can pass to the Synchronize method. I need to somehow 
retrieve the current thread in which  my event handler dispatcher is 
running, so that it can be passed to the Synchronize method. I have found 
the procedure GetCurrentThreadID, but this returns the ID of the current 
thread. Is there a way of converting a thread handle or ID to a thread 
object? (I doubt it, but I ask the question anyway). Or is there  a 
Synchronize method equivalent that can be passed a thread handle or ID in 
lieu of a TThread object?

I can see that an alternative approach could be not to attempt to call the 
event dispatcher from the thread that it happens to be running in, but to 
post a message to the application window to ensure that the event handler is 
executed in the main thread.

I note in passing that it would be very nice if a critical section object 
were to expose the threads that are waiting on it. An elegant solution could 
then have been to retrieve the current thread from the critical section, 
assuming that the current thread is the thread which currently has ownership 
of the critical section. I would have thought that under the hood a critical 
section must contain a queue of waiting threads. But unfortunately the 
Delphi TCriticalSection exposes none of this.

Any suggestions about how to dispatch the event handler in a thread-safe 
manner?

TIA,

EM
Re: How to dispatch an event handler in a thread-safe way
#180
Author: Peter Below (TeamB)
Date: Sun, 13 Jul 2008 08:18
36 lines
2274 bytes
Enquiring Mind wrote:

> Hi,
> 
> I have an object class which is designed to be used concurrently by
> multiple threads. It owns a critical section which threads can use to
> acquire exclusive access to the object before calling one of the
> object's methods. The class also exposes an event intended to be used
> to hold an event handler that updates the user interface.
> 
> The problem is how to dispatch the event handler in a thread-safe
> way. The obvious solution is to call the  TThread class method
> Synchronize, but because my class is not a thread class descendent,
> it does not have a thread object that it can pass to the Synchronize
> method.

The TThread class has an overload for Synchronize that is a class
method, it does not actually require an instance of the tthread class.
You just call it as

    TThread.Synchronize(nil, yourMethod);

Another way to do this would be to post a message to a receiver window
created in the main thread (preferrably via AllocateHwnd, since form
handles can change during the lifetime of an application). This gives
you an asynchronous notification, use SendMessage if you need a
synchronous one.



-- 
Peter Below (TeamB)  
Don't be a vampire (http://slash7.com/pages/vampires), 
use the newsgroup archives :
http://www.tamaracka.com/search.htm
http://groups.google.com
Re: How to dispatch an event handler in a thread-safe way
#186
Author: Enquiring Mind
Date: Mon, 14 Jul 2008 14:56
47 lines
3546 bytes
"Peter Below (TeamB)" <none@nomail.please> wrote in message 
news:xn0fsmmb31ckmo001@newsgroups.borland.com...
>
> The TThread class has an overload for Synchronize that is a class
> method, it does not actually require an instance of the tthread class.
> You just call it as
>
>    TThread.Synchronize(nil, yourMethod);
>
Many thanks. When I first tried this approach, I thought it didn't work, and 
I concluded (probably incorrectly) that the first parameter, which is a 
thread object reference,  must match the thread from which the Synchronize 
method is called so that Synchronize knows which thread to return to once 
the method to be synchronized has been completed in the main thread. However 
since then I have tried the same approach in a different context, where it 
seems to work. So there may have been something else in the first context 
that caused the thread to be blocked when the Synchronize method was called 
with nil as the thread reference. Can you confirm that when the thread 
parameter is set to nil as in your example, Synchronize uses and returns to 
the thread that it happens to be called from?

> Another way to do this would be to post a message to a receiver window
> created in the main thread (preferrably via AllocateHwnd, since form
> handles can change during the lifetime of an application). This gives
> you an asynchronous notification, use SendMessage if you need a
> synchronous one.
>
When I couldn't get the first approach to work in the first context, I 
switched to this message-based approach, and so far it has worked fine. 
However, not being familiar with the pitfalls of operating directly with 
window handles, I just used Application.MainForm.Handle for the destination 
window handle, and am considering changing this to the actual control that 
is to be updated, i.e. FControl.Handle, where FControl is a local field of 
the thread-safe object that holds a reference to the control where messages 
are to be sent.  Are you saying that the handles I have used and am 
considering using could change during the lifetime of the application?

I saw in some previous thread a discussion about the relative merits of a 
message-based  approach. It seemed to suggest that when using the PostMesage 
function to send a message to a destination control, there is the 
possibility that the message will be lost along the way. Is that correct, 
and does it matter?

Regards,

EM
Re: How to dispatch an event handler in a thread-safe way
#187
Author: Martin James
Date: Mon, 14 Jul 2008 15:40
36 lines
2871 bytes
>
> I saw in some previous thread a discussion about the relative merits of a 
> message-based  approach. It seemed to suggest that when using the 
> PostMesage function to send a message to a destination control, there is 
> the possibility that the message will be lost along the way. Is that 
> correct, and does it matter?

No, it is not.  Windows does not lose messages.  Windows Message Queues are 
the main method for inter-thread comms in Windows.  Losing messages would 
put Windows into the 'BSOD/crash even before the desktop appears' category. 
A PostMessage API call will fail of the handle to which is is posted is 
invalid or if there are more than <a huge number, like 10000> of messages 
are queued up.

Posting to a VCL form handle introduces the remote possibility that the 
handle may become invalid during the message transit because the target 
window has its handle recreated.  Even thsi remote possiblity can be avoided 
by posting to a window whose handle will not change because it has only one 
winproc handler whose only action is to 'forward' the received messages 
using the TForm.Perform() method.   Such a window can be created/obtained by 
means of the AllocateHwnd Delphi method, as suggested by Peter. or the 
RegisterWindowClass/CreateWindow APIs.  Messages to such a window could 
contain the target form *instance reference* as one parameter, (so that the 
winproc knows which form to call 'perform' on),  and some other 
object/whatever as the other.

Windows messages do not get lost.  PostMessage has not changed since Windows 
3.1 and cannot be allowed to fail or change, else 99% of all household 
apps/services/COM/whatever will break completely and immediately upon 
loading.  PostMessage works from any thread without any reference to the 
sending thread required.

Dump 'synchronize' now - you know it makes sense <g>

Rgds,
Martin
Re: How to dispatch an event handler in a thread-safe way
#189
Author: Peter Below (TeamB)
Date: Mon, 14 Jul 2008 17:48
41 lines
2542 bytes
Enquiring Mind wrote:

> Can you confirm that when the thread parameter is set to nil as in
> your example, Synchronize uses and returns to the thread that it
> happens to be called from?

Look at the source and your questions will be answered <g>.

> When I couldn't get the first approach to work in the first context, 
> I switched to this message-based approach, and so far it has worked 
> fine. However, not being familiar with the pitfalls of operating
directly
> with window handles, I just used Application.MainForm.Handle for the 
> destination window handle, and am considering changing this to the 
> actual control that is to be updated, i.e. FControl.Handle, where
FControl
> is a local field of the thread-safe object that holds a reference to
the
> control where messages are to be sent.  

Not safe at all. If the control dies on the thread the very attempt to
access the Handle field to send a message to it will cause an access
violation.

> Are you saying that the handles I have used and am considering using
could
> change during the lifetime of the application?

They can change. Whether they actually do depends on whether you change
certain form properties in code during the lifetime of the form. Some
property changes (to Border, Bordericon, for example) cause the VCL to
destroy and recreate the forms window handle, and with it all handles
for the controls.


-- 
Peter Below (TeamB)  
Don't be a vampire (http://slash7.com/pages/vampires), 
use the newsgroup archives :
http://www.tamaracka.com/search.htm
http://groups.google.com
Re: How to dispatch an event handler in a thread-safe way
#190
Author: Peter Below (TeamB)
Date: Mon, 14 Jul 2008 17:51
23 lines
1982 bytes
Enquiring Mind wrote:

> I saw in some previous thread a discussion about the relative merits
> of a message-based  approach. It seemed to suggest that when using
> the PostMesage function to send a message to a destination control,
> there is the possibility that the message will be lost along the way.
> Is that correct, and does it matter?

Oh, I forgot to answer that paragraph: PostMessage can loose a message
if the target threads message queue is full (a very unlikely event) or
the handle used is invalid. You can check the functions return code to
see whether it succeeded. There is also a theorical way to loose a
message *after* it was successfully posted: that happens if the target
window or the threads message queue is destroyed before the message is
processed. Typically that will only happen when the application closes
anyway.

-- 
Peter Below (TeamB)  
Don't be a vampire (http://slash7.com/pages/vampires), 
use the newsgroup archives :
http://www.tamaracka.com/search.htm
http://groups.google.com
Re: How to dispatch an event handler in a thread-safe way
#191
Author: Marc Rohloff [TeamB]
Date: Mon, 14 Jul 2008 18:31
16 lines
1875 bytes
On 14 Jul 2008 10:48:35 -0700, Peter Below (TeamB) wrote:

> They can change. Whether they actually do depends on whether you change
> certain form properties in code during the lifetime of the form. Some
> property changes (to Border, Bordericon, for example) cause the VCL to
> destroy and recreate the forms window handle, and with it all handles
> for the controls.

With the caveat that the form's handle could land up being created in
the secondary thread and not the main thread.

FWIW, I have never seen anyone check the return value of PostMessage.

-- 
Marc Rohloff [TeamB]
marc -at- marc rohloff -dot- com
Re: How to dispatch an event handler in a thread-safe way
#199
Author: Enquiring Mind
Date: Tue, 15 Jul 2008 10:26
30 lines
2461 bytes
"Martin James" <nospam@tuthill.com> wrote in message 
news:487b7361@newsgroups.borland.com...
>
> Dump 'synchronize' now - you know it makes sense <g>
>
Thanks for that.

Making a thread post a message to a UI component to request the execution of 
a UI update method does in many cases make sense, but at the same time 
entails problems of its own. The main problem is that if the UI update 
method accesses any fields of the thread object that posted the message, 
this is done concurrently with access to the same fields by the thread. 
Therefore some form of critical section must be included to protect the 
thread fields from concurrent access. In the case of Synchronize, this is 
not *normally* necessary, because while the synchronized UI update method is 
accessing thread fields in the main thread, the secondary thread is 
suspended, so cannot access the fields at the same time.

In summary, the use of PostMessage obliges one to introduce additional 
critical section objects to protect thread field accesses, whereas the use 
of Synchronize normally does not.

However, in special cases where other secondary threads may access the 
fields of the secondary thread that called the Synchronize method, a 
critical section is required even when Synchronize is used.

Regards,

EM
Re: How to dispatch an event handler in a thread-safe way
#200
Author: Enquiring Mind
Date: Tue, 15 Jul 2008 10:46
46 lines
3073 bytes
"Peter Below (TeamB)" <none@nomail.please> wrote in message 
news:xn0fsofuf2ewxp003@newsgroups.borland.com...

>> When I couldn't get the first approach to work in the first context,
>> I switched to this message-based approach, and so far it has worked
>> fine. However, not being familiar with the pitfalls of operating
> directly
>> with window handles, I just used Application.MainForm.Handle for the
>> destination window handle, and am considering changing this to the
>> actual control that is to be updated, i.e. FControl.Handle, where
> FControl
>> is a local field of the thread-safe object that holds a reference to
> the
>> control where messages are to be sent.
>
> Not safe at all. If the control dies on the thread the very attempt to
> access the Handle field to send a message to it will cause an access
> violation.
>
Is the control that dies destroyed by the application code, or by the OS? 
Clearly if the application code destroys the control, it can and must assign 
nil to  the thread's reference to the control at the same time, in order to 
ensure that the state of the thread object is kept fully synchronized with 
that of the control with which it interacts.

>> Are you saying that the handles I have used and am considering using
> could
>> change during the lifetime of the application?
>
> They can change. Whether they actually do depends on whether you change
> certain form properties in code during the lifetime of the form. Some
> property changes (to Border, Bordericon, for example) cause the VCL to
> destroy and recreate the forms window handle, and with it all handles
> for the controls.
>
That's useful to know! But although the handles of the controls may change, 
presumably the VCL control references don't change. So if a thread stores a 
reference to the control that is to be sent messages, rather than the 
control's handle, messages should still reach the control, irrespective of 
any handle change - or doesn't it work like that?

Regards,

EM
 
Re: How to dispatch an event handler in a thread-safe way
#202
Author: Marc Rohloff [TeamB]
Date: Tue, 15 Jul 2008 14:36
25 lines
2477 bytes
On Tue, 15 Jul 2008 11:46:43 +0100, Enquiring Mind wrote:

> That's useful to know! But although the handles of the controls may change, 
> presumably the VCL control references don't change. So if a thread stores a 
> reference to the control that is to be sent messages, rather than the 
> control's handle, messages should still reach the control, irrespective of 
> any handle change - or doesn't it work like that?

No, there are a couple of things that could happen.

1) The thread posts the messages to a handle successfully but, before
the message is handled, something causes the form or control to
recreate its handle.

2) The form (or control) has no handle. This can happen because it is
not yet visible or because something has happened that requires the
handle to be recreated (In this case the handle is released
immediately and a new handle is only created when it is required)
In this case, when the thread request a handle to post messages to,
the handle will be created in the context of the thread, which is 'not
a good thing'(tm)

-- 
Marc Rohloff [TeamB]
marc -at- marc rohloff -dot- com
Re: How to dispatch an event handler in a thread-safe way
#204
Author: Enquiring Mind
Date: Tue, 15 Jul 2008 16:48
35 lines
2695 bytes
"Marc Rohloff [TeamB]" <marc@nospam.marcrohloff.com> wrote in message 
news:72gsio2aix3b.dlg@dlg.marcrohloff.com...
>
> No, there are a couple of things that could happen.
>
> 1) The thread posts the messages to a handle successfully but, before
> the message is handled, something causes the form or control to
> recreate its handle.
>
Doesn't this (infinitesimal) risk apply to any message posted to a control? 
Consider the following code:

 if (FControl<>nil) and (FControl.Handle>0) and (FOnChangeMessage<>0) then
    PostMessage(FControl.Handle, FOnChangeMessage, cardinal(Self), 0);

This should retrieve the handle of the destination control just before 
PostMessage is called, so the handle should be completely up-to-date. Since 
PostMessage is asynchronous, the message should reach the destination queue 
very quickly, hopefully before the destination control's handle has had a 
chance to change.

> 2) The form (or control) has no handle. This can happen because it is
> not yet visible or because something has happened that requires the
> handle to be recreated (In this case the handle is released
> immediately and a new handle is only created when it is required)
> In this case, when the thread request a handle to post messages to,
> the handle will be created in the context of the thread, which is 'not
> a good thing'(tm)
>
Can't we can check for this before calling PostMessage, as in the above?

Regards,

EM
Re: How to dispatch an event handler in a thread-safe way
#206
Author: Peter Below (TeamB)
Date: Tue, 15 Jul 2008 17:49
34 lines
2299 bytes
Enquiring Mind wrote:

> > Not safe at all. If the control dies on the thread the very attempt
> > to access the Handle field to send a message to it will cause an
> > access violation.
> > 
> Is the control that dies destroyed by the application code, or by the
> OS?

By application code or the VCL, when the form hosting the control is
destroyed.

> Clearly if the application code destroys the control, it can and
> must assign nil to  the thread's reference to the control at the same
> time, in order to ensure that the state of the thread object is kept
> fully synchronized with that of the control with which it interacts.

Definitely. One could alternatively make use of the notification
mechanism build into the VCL for components (FreeNotification et al.).
I would prefer that since it allows the thread object itself to detect
when the control reference is about to become invalid. That's allways
more dependable than having to remember elsewhere to set the control
reference to nil before the control dies.

The control reference is unchanged when the handle changes, by the way. 



-- 
Peter Below (TeamB)  
Don't be a vampire (http://slash7.com/pages/vampires), 
use the newsgroup archives :
http://www.tamaracka.com/search.htm
http://groups.google.com
Re: How to dispatch an event handler in a thread-safe way
#207
Author: Marc Rohloff [TeamB]
Date: Tue, 15 Jul 2008 18:37
19 lines
2122 bytes
On Tue, 15 Jul 2008 17:48:55 +0100, Enquiring Mind wrote:

> Doesn't this (infinitesimal) risk apply to any message posted to a control? 
Yes, though I wouldn't call it infinitesimal. I also know all the fun
some people have had trying to debug this issue.

>  if (FControl<>nil) and (FControl.Handle>0) 
You are aware that calling FControl.Handle will actually create the
handle if it hasn't been created yet? You need to call
FControl.HandleAllocated.

> Can't we can check for this before calling PostMessage, as in the
> above? 
So what are you going to do then? Not send your message. That seems
almost as bad as sending it and having it get lost on the way.

-- 
Marc Rohloff [TeamB]
marc -at- marc rohloff -dot- com
Re: How to dispatch an event handler in a thread-safe way
#208
Author: Martin James
Date: Wed, 16 Jul 2008 13:19
48 lines
3603 bytes
> Making a thread post a message to a UI component to request the execution 
> of a UI update method does in many cases make sense, but at the same time 
> entails problems of its own. The main problem is that if the UI update 
> method accesses any fields of the thread object that posted the message, 
> this is done concurrently with access to the same fields by the thread. 
> Therefore some form of critical section must be included to protect the 
> thread fields from concurrent access. In the case of Synchronize, this is 
> not *normally* necessary, because while the synchronized UI update method 
> is accessing thread fields in the main thread, the secondary thread is 
> suspended, so cannot access the fields at the same time.

Yes, if you access field of the thread, (ie. don't do that!).

> In summary, the use of PostMessage obliges one to introduce additional 
> critical section objects to protect thread field accesses, whereas the use 
> of Synchronize normally does not.

No.  PostMessage has parameters whereas 'TThread.synchronize' does not.  If 
all the data required for the operation is contained in the parameters, then 
it is not necessary to access any field of the thread & so no extra 
protection is required.  32-bit parameters can be passed directly in 
wParam/lParam and, since '32-bit'  includes instance reference pointers, 
entire classe instances like buffers, sockets, subsystems can be passed 
easily with PostMessage.

> However, in special cases where other secondary threads may access the 
> fields of the secondary thread that called the Synchronize method, a 
> critical section is required even when Synchronize is used.

Yes - as above, *don't access fields of TThread objects from other threads*. 
This is unnecessary and usually dangerous/unsafe for the reasons you give 
above and others.  What happens if the TThread wants to terminate and free 
itself?  It dare not in case one of the other threads wants to access its 
fields for some reason.

If PM is used to transfer data like integers or instance references *that 
are not itself or objects that it has it itself owns and must free before 
exit*, then there is no problem - PM off whatever you like, whenever you 
like, and die straight after if you want - the PM data willl still be fine.

Rgds,
Martin




Rgds,
Martin
Re: How to dispatch an event handler in a thread-safe way
#209
Author: Enquiring Mind
Date: Wed, 16 Jul 2008 14:37
17 lines
1855 bytes
"Marc Rohloff [TeamB]" <marc@nospam.marcrohloff.com> wrote in message 
news:lqfthmiyn2qd$.dlg@dlg.marcrohloff.com...

> You are aware that calling FControl.Handle will actually create the
> handle if it hasn't been created yet? You need to call
> FControl.HandleAllocated.
>
Thanks for pointing that out.

>> Can't we can check for this before calling PostMessage, as in the
>> above?
> So what are you going to do then? Not send your message. That seems
> almost as bad as sending it and having it get lost on the way.
>
At least the application becomes aware of the potential problem before it 
occurs, and can react accordingly. 
Re: How to dispatch an event handler in a thread-safe way
#210
Author: Enquiring Mind
Date: Wed, 16 Jul 2008 15:32
64 lines
4558 bytes
"Martin James" <nospam@tuthill.com> wrote in message 
news:487df568$1@newsgroups.borland.com...
>
> Yes, if you access field of the thread, (ie. don't do that!).
>
The main reason for calling an event handler may be to display some thread 
state variables in the user interface, so you have no option but to access 
the thread's fields either directly or indirectly through a method or global 
variables.
>
> No.  PostMessage has parameters whereas 'TThread.synchronize' does not. 
> If

'TThread.synchronize' usually calls an event dispatcher, which assigns 
'Self' to the 'Sender' parameter of the TNotifyEvent. In the case of 
PostMessage, OTOH, the Sender reference has to be put in the WParam 
parameter, leaving one only one other 32-bit parameter for other data.

> all the data required for the operation is contained in the parameters, 
> then it is not necessary to access any field of the thread & so no extra 
> protection is required.  32-bit parameters can be passed directly in 
> wParam/lParam and, since '32-bit'  includes instance reference pointers, 
> entire classe instances like buffers, sockets, subsystems can be passed 
> easily with PostMessage.

If WParam contains a reference to the Thread object that sent the message, 
then there is nothing to prevent the message handler from accessing the 
(visible) fields and properties of the thread object. Thus the 
fields/properties can be accessed concurrently by the message handler and by 
the thread that sent the message. More generally, if either parameter 
contains a pointer, there is nothing to prevent concurrent access of the 
data referenced by the pointer. When pointers cross thread boundaries there 
are potential problems!

> Yes - as above, *don't access fields of TThread objects from other 
> threads*. This is unnecessary and usually dangerous/unsafe for the reasons 
> you give above and others.  What happens if the TThread wants to terminate 
> and free itself?  It dare not in case one of the other threads wants to 
> access its fields for some reason.
>
Presumably any thread wishing to access the fields of another thread could 
first check that the other thread object is assigned.

> If PM is used to transfer data like integers or instance references *that 
> are not itself or objects that it has it itself owns and must free before 
> exit*, then there is no problem - PM off whatever you like, whenever you 
> like, and die straight after if you want - the PM data willl still be 
> fine.
>
You seem to be saying that provided the two message parameters are value 
parameters, or pointers to variables that the sender doesn't own and will 
never again use, then there's no problem - agreed because value parameters 
will contain copies of the thread fields, and  pointers will only ever be 
used again by the recipient of the message. In most practical cases you need 
to transfer more data from the sender to the receiver than will fit into 2 
32-bit cardinals - e.g. a string. So whenever this is the case, the sender 
thread has to create a dynamic variable, assign the data to be transferred 
to it,  pass it by reference to a message parameter, post the message, then 
for safety immediately set the pointer to nil. The message handler has to 
dereference the pointer, copy the data into some local variables, and 
dispose of the variable.

So it can be done, but at the cost of considerable extra work! 
Re: How to dispatch an event handler in a thread-safe way
#211
Author: Martin James
Date: Thu, 17 Jul 2008 06:53
166 lines
9397 bytes
"Enquiring Mind" <Enquiring.Mind@nospam.btopenworld.com> wrote in message 
news:487e14bb@newsgroups.borland.com...
>
> "Martin James" <nospam@tuthill.com> wrote in message 
> news:487df568$1@newsgroups.borland.com...
>>
>> Yes, if you access field of the thread, (ie. don't do that!).
>>
> The main reason for calling an event handler may be to display some thread 
> state variables in the user interface, so you have no option but to access 
> the thread's fields either directly or indirectly through a method or 
> global variables.

Thread state variables?  The OS certainly keeps thread state variables, but 
I can't see, off-hand, why TThreads should have any state data that is 
required outside the TThread.  If these state variables are really state 
variables of some functionality that is not really part of the thread, then 
they should be in a class whose methods/properties are called from <some 
thread>.

>> No.  PostMessage has parameters whereas 'TThread.synchronize' does not. 
>> If
>
> 'TThread.synchronize' usually calls an event dispatcher, which assigns 
> 'Self' to the 'Sender' parameter of the TNotifyEvent. In the case of 
> PostMessage, OTOH, the Sender reference has to be put in the WParam 
> parameter, leaving one only one other 32-bit parameter for other data.

1) Does it have to  matter which thread sent the the data?  What is 'Sender' 
in the case of an inter-thread communication?

2) One 32-bit parameter is all you need anyway.  That's enough for a class 
reference, which is enough to transfer megabytes of data and hundreds of 
inherited methods around your system, should you so chose.

>> all the data required for the operation is contained in the parameters, 
>> then it is not necessary to access any field of the thread & so no extra 
>> protection is required.  32-bit parameters can be passed directly in 
>> wParam/lParam and, since '32-bit'  includes instance reference pointers, 
>> entire classe instances like buffers, sockets, subsystems can be passed 
>> easily with PostMessage.
>
> If WParam contains a reference to the Thread object that sent the message, 
> then there is nothing to prevent the message handler from accessing the 
> (visible) fields and properties of the thread object. Thus the 
> fields/properties can be accessed concurrently by the message handler and 
> by the thread that sent the message.

Yes, they can, so don't do it!  Think about it - what thread field is really 
needed outside the thread?

More generally, if either parameter
> contains a pointer, there is nothing to prevent concurrent access of the 
> data referenced by the pointer. When pointers cross thread boundaries 
> there are potential problems!

Yes, exactly, so don't do it!  Use classes/objects to supply parameters, 
perform methods and hold state data.

>> Yes - as above, *don't access fields of TThread objects from other 
>> threads*. This is unnecessary and usually dangerous/unsafe for the 
>> reasons you give above and others.  What happens if the TThread wants to 
>> terminate and free itself?  It dare not in case one of the other threads 
>> wants to access its fields for some reason.
>>
> Presumably any thread wishing to access the fields of another thread could 
> first check that the other thread object is assigned.

Nope - won't work:

1)  A TThread has two aspects - the Delphi TThread class and the OS thread 
object.  Just because one exists, there is no guarantee that the other does 
too.

2) Even if a check was possible, the check is only valid at the time it was 
made.  On the next line of code after the 'if assigned()', the thread may 
have disappeared.

>> If PM is used to transfer data like integers or instance references *that 
>> are not itself or objects that it has it itself owns and must free before 
>> exit*, then there is no problem - PM off whatever you like, whenever you 
>> like, and die straight after if you want - the PM data willl still be 
>> fine.
>>
> You seem to be saying that provided the two message parameters are value 
> parameters, or pointers to variables that the sender doesn't own and will 
> never again use, then there's no problem - agreed because value parameters 
> will contain copies of the thread fields, and  pointers will only ever be 
> used again by the recipient of the message. In most practical cases you 
> need to transfer more data from the sender to the receiver than will fit 
> into 2 32-bit cardinals - e.g. a string. So whenever this is the case, the 
> sender thread has to create a dynamic variable, assign the data to be 
> transferred to it,  pass it by reference to a message parameter, post the 
> message, then for safety immediately set the pointer to nil.


That is one way.  You seem to be fixated on using thread fields to transfer 
data in/out of secondary threads.  I think you've been looking at the 
Borland examples and 'How To Use TThread' pages on the net.  Try not to do 
that! <g>

 The message handler has to
> dereference the pointer, copy the data into some local variables, and 
> dispose of the variable.

That is certainly one way.

> So it can be done, but at the cost of considerable extra work!

Yes, but then again. often the 'considerable extra work' has already been 
done.  If the state data is not in thread fields, (where it should not be 
anyway!), but in a class instance that was supplied/queue/whatever to the 
thread, then thread fields do not have to be copied inhto/outof anywhere 
because they do not exist.  Let me try an example - a web crawler, say. 
There is probably already a class to represent a web page - it just needs 
adding to so that it can hold results/extra methods as well, eg:

TwebPage=class
    thisPage:string;
    linksOnThisPage:TstringList;
 public
    URI:string;
    getThisPage(usingThisComponent:TidHTTP);
    parsePageForLinks();
    errorMessage:string;
end;

Note:I haven't bothered with constructors etc.

The main thread could contruct one of these and use a 'plonked on form' 
TidHTTP instance to call getThispage and then parsePageForLinks.  That 
should work OK, but the main thread would freeze and so, instead, you queue 
off this instance to a thread/threads that have their own TidHTTP and let 
the thread call the methods and PostMessage the TwebPage back.  You could 
then display the links in a memo in the message-handler.  If there was some 
exception, you can return the error E.message in the field provided.  After 
displaying the links, the main thread could then construct as many new 
TwebPage instances as there are links and queue them off to the thread/s to 
follow the links - either that or, better,  have the secondary thread/s 
themselves create/issue the newTwebPage instances to themselves.

No TThread fields required outside the TThread.  No main-thread freeze, no 
main-thread involvement at all while the page/s are being retrieved.  The 
main thread does not know, or care, what TThread/TidHTTP did the work, only 
that the work got done.  This is important in apps like this because any one 
of a pool of threads could have done the work and, more importantly, that 
thread is probably already doing more work on other TwebPage instances when 
its earlier efforts are being displayed in a main-thread memo.

Any attempt to use non-locked TThread fields to hold results for display 
would be disastrous in such an app.  Using TThread.synchronize to hold up 
the TThreads until the results could be displayed would tie up the threads 
to such an extent that performance would be crippled: threads that could be 
calling TidHTTP get/post are sitting around waiting for their synchronized 
methods to get handled.  That is bad on a single processor system, worse on 
multiple cores since all the actions are held up on the one processor 
running the main thread.

Give up on all those examples of using TThread that insist on using TThread 
fields and TThread.synchronize.  I know that Borland, and most 'How to use 
TThread' examples on the net, show TThread.synchronize and TThread field use 
from outside the thread.  They all suck.

Rgds,
Martin
Re: How to dispatch an event handler in a thread-safe way
#212
Author: Enquiring Mind
Date: Thu, 17 Jul 2008 15:04
260 lines
11684 bytes
"Martin James" <nospam@tuthill.com> wrote in message 
news:487eec50@newsgroups.borland.com...
>  Thread state variables?  The OS certainly keeps thread state variables, 
> but I can't see, off-hand, why TThreads should have any state data that is 
> required outside the TThread.  If these state variables are really state 
> variables of some functionality that is not really part of the thread, 
> then they should be in a class whose methods/properties are called from 
> <some thread>.
>
The term 'thread state variable' that I used may be too general a term. A 
better term would have been 'thread variable'. By this I meant any field 
that is a member of a thread object that is accessible to other threads 
either because it's public, or because it can be accessed through a 
property. Data normally exclusive to a thread may be held in one of 3 
locations as far as I can see: a) in fields of the thread object; b) in 
local variables of the Execute method or of any method or procedure directly 
or indirectly called by it; c) in a threadvar variable. (Perhaps you might 
like to elucidate the relative pros and cons of these 3 types of thread 
storage).

Having defined what I mean by a thread state variable, then it's a matter 
for a particular application whether or not a thread variable always remains 
for ever private to the thread, or whether there is a need for it to be 
communicated to another thread, so that, for example, it can be displayed in 
the user interface.


>>
>> 'TThread.synchronize' usually calls an event dispatcher, which assigns 
>> 'Self' to the 'Sender' parameter of the TNotifyEvent. In the case of 
>> PostMessage, OTOH, the Sender reference has to be put in the WParam 
>> parameter, leaving one only one other 32-bit parameter for other data.
>
> 1) Does it have to  matter which thread sent the the data?  What is 
> 'Sender' in the case of an inter-thread communication?
>
It matters if the main thread needs to access the thread's fields or 
properties in an event handler declared in say the main form and assigned to 
an event exposed by a particular TTthread descendent class. Howveer, this is 
only one of several methods for transferring data between threads!

> 2) One 32-bit parameter is all you need anyway.  That's enough for a class 
> reference, which is enough to transfer megabytes of data and hundreds of 
> inherited methods around your system, should you so chose.
>
Agreed.


>> If WParam contains a reference to the Thread object that sent the 
>> message, then there is nothing to prevent the message handler from 
>> accessing the (visible) fields and properties of the thread object. Thus 
>> the fields/properties can be accessed concurrently by the message handler 
>> and by the thread that sent the message.
>
> Yes, they can, so don't do it!  Think about it - what thread field is 
> really needed outside the thread?
>
I agree it's desirable to avoid this, but the concurrent access issue can be 
controlled by various means, like Synchronize, TCriticalSection objects, 
etc.

> More generally, if either parameter
>> contains a pointer, there is nothing to prevent concurrent access of the 
>> data referenced by the pointer. When pointers cross thread boundaries 
>> there are potential problems!
>
> Yes, exactly, so don't do it!  Use classes/objects to supply parameters, 
> perform methods and hold state data.
>

>> Presumably any thread wishing to access the fields of another thread 
>> could first check that the other thread object is assigned.
>
> Nope - won't work:
>
> 1)  A TThread has two aspects - the Delphi TThread class and the OS thread 
> object.  Just because one exists, there is no guarantee that the other 
> does too.
>
> 2) Even if a check was possible, the check is only valid at the time it 
> was made.  On the next line of code after the 'if assigned()', the thread 
> may have disappeared.

Good point. However thread A can request the suspension of thread B, and 
when suspended access some of its properties, and  finally resume thread B.

>
> That is one way.  You seem to be fixated on using thread fields to 
> transfer data in/out of secondary threads.  I think you've been looking at 
> the Borland examples and 'How To Use TThread' pages on the net.  Try not 
> to do that! <g>
>
> The message handler has to
>> dereference the pointer, copy the data into some local variables, and 
>> dispose of the variable.
>
> That is certainly one way.
>
After further thought I have concluded that the way I described is the 
safest way of transferring data when using *messages* to communicate between 
threads (that is, without resorting to a critical section, which would 
defeat the object of using PostMessage instead of Synchronize). The sender, 
say thread A, creates a container object and copies thread state data to the 
container object. It then sends the recipient, say thread B, a message, 
including in it a reference to the container object, and from this point in 
time on thread A *never* again accesses the container object. Thread B in 
the message handler copies data from the container, processes tha data as 
necessary, then destroys the container object. Since the data in the 
container object can *never* be accessed concurrently by more than one 
thread, this approach must be as safe as houses.

However when you are using Synchronize there is an even better way of 
transferring state data in such a way as to preclude the possibility of 
concurrent access - in 'by-value' parameters of the event handler. These 
exist for only as long as the event handler exists on the stack. The most 
general by-value paramter could be a byte array containing the data to be 
transferred in the form of a binary stream.

>
> Yes, but then again. often the 'considerable extra work' has already been 
> done.  If the state data is not in thread fields, (where it should not be 
> anyway!), but in a class instance that was supplied/queue/whatever to the 
> thread, then thread fields do not have to be copied inhto/outof anywhere 
> because they do not exist.

If a thread holds data, which under normal use is exclusive to itself, in an 
object, then this is just an extension of a thread field. The thread still 
needs a field containing a reference to the said object, and the thread 
should usually own the object. The thread cannot just pass a reference to 
this object to another thread an expect concurrent acces to be prevented. 
Even if the object comes from a queue, the queue itself will be shared by 
multiple threads.

>Let me try an example - a web crawler, say.

Many thanks for the example - I will study it with interest. But I don't 
know enough about web programming to make any meaningful comments on it at 
the moment!

I have an example of the approach I have been describing. It uses the 
dreaded TTcpServer component. I had to use messages to transmit data between 
the OnAccept method handler (that runs in a client socket thread) and the 
main form, because without deriving a new thread class from 
TClientSocketThread defined in the VCL, I cannot add events or event 
disptachers to the thread class. The (tested) code is below:

const
  WM_ClientSocketThread_Cycle= WM_APP + 3;

type
  {The following class encapsulates data to be transmitted from client 
socket thread to main thread}
  TCycleState= class
    MessageCount: integer;
    LastMessage: string;
    ThreadID: integer;
  end;

TForm1 = class(TForm)
    TcpServer1: TTcpServer;
    {...}
    procedure TcpServer1Accept(Sender: TObject;
      ClientSocket: TCustomIpClient);
    {...}
  private
   {...}
    {Thread event handlers:}
    procedure ThreadSocketEchoOnCycle(MessageCount: integer; LastMessage: 
string;
        ThreadId: integer);
  protected
    procedure WMClientSocketThreadCycle(var Msg: TMessage);
                                 message WM_ClientSocketThread_Cycle;
  public
    { Public declarations }
  end;

implementation

procedure TForm1.TcpServer1Accept(Sender: TObject;
  ClientSocket: TCustomIpClient);
  {Important note: This event handler runs inside the client socket thread 
created
   by the TcpServer component.}
var
  CurrClientSocketThread: TClientSocketThread;
    {Thread created for current connection, under which this method is 
running}

  procedure DoListen;
  {This option listens for messages on a single connection -  for 
illustrative
   purposes only}
  var
    MessageCount: integer;
    LastMessage: string;
    Terminated1: Boolean;
    Response: string;
    CycleState: TCycleState;
  begin
    Terminated1:= False;
    MessageCount:= 0;
    repeat
      {Receive next message on socket:}
      LastMessage:= ClientSocket.Receiveln;
      Inc(MessageCount);
      {Notify cycle to enable UI to be updated:}
      CycleState:= TCycleState.Create;  {Create container object}
      CycleState.LastMessage:= LastMessage;
      CycleState.MessageCount:= MessageCount;
      CycleState.ThreadID:= CurrClientSocketThread.ThreadID;
      PostMessage(Form1.Handle, WM_ClientSocketThread_Cycle, 
Cardinal(CycleState), 0);
      CycleState:= nil; {Not needed, but included to emphasize the point!}
      {Determine response:}
      if (LastMessage= 'quit') or (LastMessage= '') then
        begin
          Terminated1:= True;
          Response:= 'Terminated';
        end
      else
        Response:= 'Echo: ' + LastMessage;
      {Send response:}
      ClientSocket.SendLn(Response);
    until Terminated1;
  end;

begin
  {Retrieve current client socket thread}
  CurrClientSocketThread:= ClientSocket.GetThreadObject;
  try
     {Notify client that connection has been made:}
    ClientSocket.SendLn('You are connected');
    {Perform thread cycles}
    DoListen;
  finally
    {Clean up...}
  end;
end;

procedure TForm1.WMClientSocketThreadCycle(var Msg: TMessage);
{Message handler}
var
  CycleState: TCycleState;
begin
  {Retrieve reference to container object from message:}
  CycleState:= TObject(Msg.WParam)  as TCycleState;
  {Process data transferred in an event handler:}
  with CycleState do
    ThreadSocketEchoOnCycle({.}MessageCount, {.}LastMessage, {.}ThreadID);
  {Destroy container:}
  CycleState.Free;
end;

Any comments?

Regards,

EM
Re: How to dispatch an event handler in a thread-safe way
#118
Author: Enquiring Mind
Date: Fri, 18 Jul 2008 11:03
139 lines
7077 bytes
"Martin James" <nospam@tuthill.com> wrote in message 
news:487eec50@newsgroups.borland.com...
>
>  Let me try an example - a web crawler, say. There is probably already a 
> class to represent a web page - it just needs adding to so that it can 
> hold results/extra methods as well, eg:
>
> TwebPage=class
>    thisPage:string;
>    linksOnThisPage:TstringList;
> public
>    URI:string;
>    getThisPage(usingThisComponent:TidHTTP);
>    parsePageForLinks();
>    errorMessage:string;
> end;
>
> Note:I haven't bothered with constructors etc.
>
> The main thread could contruct one of these and use a 'plonked on form' 
> TidHTTP instance to call getThispage and then parsePageForLinks.  That 
> should work OK, but the main thread would freeze and so, instead, you 
> queue off this instance to a thread/threads that have their own TidHTTP 
> and let the thread call the methods and PostMessage the TwebPage back. 
> You could then display the links in a memo in the message-handler.  If 
> there was some exception, you can return the error E.message in the field 
> provided.  After displaying the links, the main thread could then 
> construct as many new TwebPage instances as there are links and queue them 
> off to the thread/s to follow the links - either that or, better,  have 
> the secondary thread/s themselves create/issue the newTwebPage instances 
> to themselves.
>
Now that I've had time to partially digest your example, I would make the 
following comments. Both the main thread and the thread created to fetch the 
web page in the background have concurrent access to the same TWebPage 
object. Therefore the fields of this object are not *inherently* 
thread-safe, because while a secondary thread is downloading the web page 
into the ThisPage field, the main thread could be trying to access the 
ThisPage field, for example to repaint the user interface. Of course, this 
can be avoided by good programming, but it would be nice if the program 
structure could exclude the possibility at source!

In essence, the reason for using a thread is to execute a single lengthy 
procedure in the background, and when it terminates, to communicate the 
results of the lengthy procedure to the main thread, so that they can be 
displayed in the user interface. With only a marginal loss of efficiency 
this could be more simply accomplished by communicating the results in an 
OnTerminate event handler assigned to the thread. It's true that this is 
synchronized, but it only happens once in the life of the thread - just 
before it is destroyed - so the loss in efficiency seems marginal. Moreover, 
the execution of the OnTerminate handler is fast compared to the execution 
of the Execute method of the thread, because it just copies the data from a 
couple of secondary thread variables to main thread variables. I am not sure 
whether the secondary thread dispatches the OnTerminate event handler 
synchronously or asynchronously, but because of its speed, it shouldn't 
matter too much even if the call is synchronous. There should be no great 
loss in efficiency even when multiple threads try to dispatch the 
OnTerminate event handler at precisely the same time. The OnTerminate event 
handler can copy the data in thread fields to user interface variables 
without using a critical section in the certainty that the thread won't be 
accessing the fields at the same time - after all the thread procedure has 
terminated. For better performance, one can by all means use the PostMessage 
approach, and post the message when the thread terminates.

The pseudo-code for the alternative approach (without using a thread pool, 
and omitting all error handling) could be:

TThreadFetchWebpage= class(TThread)
private
  FURI: string;
  FWebpage: string;   {Owned by thread}
  FLinksOnPage: TStringList;  {Owned by thread}
protected
  procedure Execute; override;
public
  constructor Create(CreateSuspended: boolean; URI: string);
  destructor Destroy; override;  {Frees stringlist etc}
  procedure GetOutputData(var Webpage: string; LinksOnPage: TStringList);
end;

procedure TThreadFetchWebpage.Execute;
var
  idHTTP: TidHTTP;
begin
  idHTTP:= TidHTTP.Create(nil);
  try
    {Code to download web page into FWebpage using idHTTP component:}
      ..
    {Code to extract links from FWebpage into FLinksOnPage:}
    ...
  finally
    idHTTP.Free;
  end;
end;

procedure TThreadFetchWebpage.GetOutputData(var Webpage: string; 
LinksOnPage: TStringList);
begin
  {*Copy* data, not references:}
  Webpage:= Copy(FWebpage, ...);
  LinksOnPage.Text:= FLinksOnPage.Text;
end;

procedure TForm1.ThreadFetchWebpageTerminate(Sender: TObject);
var
   ThreadFetchWebpage: TThreadFetchWebpage;
begin
   ThreadFetchWebpage:= Sender as TThreadFetchWebpage;
   {Copy results from thread into form fields:}
   ThreadFetchWebpage.GetOutputdata(Self.FWebpage, Self.FLinksOnPage);
   {Destroy thread}
   ThreadFetchWebpage.Free;
   {Update user interface}
   DataToControls;
   Invalidate;
end;

procedure TForm1.ButtonFetchWebpageClick(Sender: TObject);
var
  URI: string;
  ThreadFetchWebpage: TThreadFetchWebpage;
begin
  URI:= EditURI.Text;
  {Create thread to fetch web page:}
  ThreadFetchWebpage:=  TThreadFetchWebpage.Create(True, URI);
  ThreadFetchWebpage.OnTerminate:= ThreadFetchWebpageTerminate;
  {Start thread:}
  ThreadFetchWebpage.Resume;
end;

This assumes that if the user clicks the fetch button several times in rapid 
succession, the form only displays the last web page to reach it. An 
alternative approach would be to create a new tabsheet for each web page 
fetched.

Regards,

EM
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads