From: Joseph M. Newcomer on
See below...
On Sun, 02 May 2010 06:59:11 -0400, Hector Santos <sant9442(a)nospam.gmail.com> wrote:

>
>Joseph M. Newcomer wrote:
>
>
>> Typically, what I would do is create a thread to fetch the data, and when the data is
>> received, use PostMessage to post a pointer to that data back to the main GUI thread; the
>> main GUI thread then uses the pointer in some reasonable fashion.
>
>
>But does that not defeat the purpose of blocking the UI again - the original OP issue? I agree, grabbing a copy of a external thread data, but posting it back to the GUI isn't solving the issue.
****
It depends on the tradeoff. The OP suggested that the major delay was in obtaining the
remote data, not in processing it (e.g., putting the text in the HTML control). So using
a secondary thread to obtain the data allows the main thread to do other things, but it
doesn't change the total delay in presenting the information (in the absolute sense, it
increases the latency, because of the interthread communication, but that overhead is
generally so small as to be unnoticeable compared to the other costs)

But the UI thread is not blocked during the download-data phase, and consequently, in
spite of the fact that the desired data is not being displayed, the thread can handle
other user interactions.

This leads to potentially nasty race conditions, e.g., the window is up, the user starts a
download, and closes the window before the download completes. An attempt to PostMessage
to the CWnd * will probably take an access fault, and a PostMessage to the HWND will be
discarded, thus resulting, most likely, in a memory leak (and ::IsWindow is insufficient
to handle this). So a window that has a pending PostMessage must not actually allow
itself to be destroyed (the most common solution I use is to hide the window, thus
providing the user with the illusion that the window has been "closed", but the window
itself is still live; when the pending transaction completes, it merely discards the data
and completes the window destruction...this takes a fair amount of careful coding).
****
>
>
>> The long explanation about the message pump is important and you really need to understand
>> that.
>
>
>Joe, there are many time where a short explanation or reference that pertains the OP issue suffices. Its really not that hard to advise a solution that does not requires a course in MFC 101. It saves you time too. If there is any follow up questions, then you can provide with a course in MFC 101 message pumps.
****
Actually, I was citing your careful explanation! I saw no reason to duplicate it, since
you did such a good job, but I wanted to emphasize that this knowledge is critical.

It isn't "MFC 101" it is "Elementary Windows Fundamentals"
joe

****
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Goran on
On May 2, 4:39 am, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> Generally, you can pass any pointer across thereads.  However, there are some limitations
> which are not always obvious.

Attention, he stated that he wants to pass a COM interface pointer.
That can't be passed to another thread. You kinda missed the boat with
the explanation that follows.

>
> For example, both threads have to share the same heap and use the same allocator for
> new/malloc delete/free.  This is the most common scenario, and therefore this requirement
> is usually not mentioned or even noticed.
>
> But if the thread is in a DLL that has static linking of the CRT, you are doomed.
>
> Typically, what I would do is create a thread to fetch the data, and when the data is
> received, use PostMessage to post a pointer to that data back to the main GUI thread; the
> main GUI thread then uses the pointer in some reasonable fashion.
>
> The long explanation about the message pump is important and you really need to understand
> that.


Goran.
From: Goran on
On May 2, 6:05 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> It depends on the tradeoff.  The OP suggested that the major delay was in obtaining the
> remote data, not in processing it (e.g., putting the text in the HTML control).  So using
> a secondary thread to obtain the data allows the main thread to do other things, but it
> doesn't change the total delay in presenting the information (in the absolute sense, it
> increases the latency, because of the interthread communication, but that overhead is
> generally so small as to be unnoticeable compared to the other costs)
>
> But the UI thread is not blocked during the download-data phase, and consequently, in
> spite of the fact that the desired data is not being displayed, the thread can handle
> other user interactions.
>
> This leads to potentially nasty race conditions, e.g., the window is up, the user starts a
> download, and closes the window before the download completes.  An attempt to PostMessage
> to the CWnd * will probably take an access fault, and a PostMessage to the HWND will be
> discarded, thus resulting, most likely, in a memory leak (and ::IsWindow is insufficient
> to handle this).  So a window that has a pending PostMessage must not actually allow
> itself to be destroyed (the most common solution I use is to hide the window, thus
> providing the user with the illusion that the window has been "closed", but the window
> itself is still live; when the pending transaction completes, it merely discards the data
> and completes the window destruction...this takes a fair amount of careful coding).

Some simple shared_ptr/weak_ptr juggling work wonders for this. Here's
an example:

* Window (UI thread) creates a heap object that needs to passed to the
main thread and puts it in a shared_ptr. Window keeps that shared_ptr.
Object contains a copy of window's HWND (NOT a reference/ptr to a
CWnd).
* thread stores a weak_ptr to the object. It turns it into a
shared_ptr ONLY when it actually needs to use the object (it must
watch out for NULL).
* when window gets destroyed, it resets shared_ptr.
* thread uses PostMessage with object's HWND to inform the window that
data is ready or whatever. Now... If PostMessage fails because window
has been closed in the meantime, no biggie: object goes away when last
shared_ptr goes away. (Remember: shared_ptr is either held
"permanently" by the window, either "temporarily" by he thread). If
message is delivered, window can use data that is in the object
(remember, window has a shared_ptr to it). Thread might or might not
go away, that's without influence.

This is quite simple, yet effective. Only downside is that object must
be ready to be destroyed in ether thread. But I did not find this to
be an issue - if object contains stuff that has thread affinity, it's
not very eligible to be passed around threads anyhow.

Goran.
From: Joseph M. Newcomer on
See below...
On Sun, 2 May 2010 11:52:02 -0700 (PDT), Goran <goran.pusic(a)gmail.com> wrote:

>On May 2, 6:05�pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>> It depends on the tradeoff. �The OP suggested that the major delay was in obtaining the
>> remote data, not in processing it (e.g., putting the text in the HTML control). �So using
>> a secondary thread to obtain the data allows the main thread to do other things, but it
>> doesn't change the total delay in presenting the information (in the absolute sense, it
>> increases the latency, because of the interthread communication, but that overhead is
>> generally so small as to be unnoticeable compared to the other costs)
>>
>> But the UI thread is not blocked during the download-data phase, and consequently, in
>> spite of the fact that the desired data is not being displayed, the thread can handle
>> other user interactions.
>>
>> This leads to potentially nasty race conditions, e.g., the window is up, the user starts a
>> download, and closes the window before the download completes. �An attempt to PostMessage
>> to the CWnd * will probably take an access fault, and a PostMessage to the HWND will be
>> discarded, thus resulting, most likely, in a memory leak (and ::IsWindow is insufficient
>> to handle this). �So a window that has a pending PostMessage must not actually allow
>> itself to be destroyed (the most common solution I use is to hide the window, thus
>> providing the user with the illusion that the window has been "closed", but the window
>> itself is still live; when the pending transaction completes, it merely discards the data
>> and completes the window destruction...this takes a fair amount of careful coding).
>
>Some simple shared_ptr/weak_ptr juggling work wonders for this. Here's
>an example:
>
>* Window (UI thread) creates a heap object that needs to passed to the
>main thread and puts it in a shared_ptr. Window keeps that shared_ptr.
>Object contains a copy of window's HWND (NOT a reference/ptr to a
>CWnd).
****
It is a common myth that you can't pass a CWnd* across thread boundaries. This is an
oversimplication of a much more subtle issue: you can't access the HWND of a CWnd *, and
you must ensure the lifetime of the CWnd * exceeds the time the thread can access it.

Passing an HWND is more conservative, but leads to a whole NEW set of problems, which are
actually more dangerous to the uninitiated.
****
>* thread stores a weak_ptr to the object. It turns it into a
>shared_ptr ONLY when it actually needs to use the object (it must
>watch out for NULL).
>* when window gets destroyed, it resets shared_ptr.
>* thread uses PostMessage with object's HWND to inform the window that
>data is ready or whatever. Now... If PostMessage fails because window
>has been closed in the meantime, no biggie: object goes away when last
>shared_ptr goes away. (Remember: shared_ptr is either held
>"permanently" by the window, either "temporarily" by he thread). If
>message is delivered, window can use data that is in the object
>(remember, window has a shared_ptr to it). Thread might or might not
>go away, that's without influence.
****
Yes. And this tends to still require that the same heap be visible; as far as I know the
shared_ptr doesn't carry its allocator/deallocator information with it. But I could be
wrong; I haven't looked at this in a couple years
****
>
>This is quite simple, yet effective. Only downside is that object must
>be ready to be destroyed in ether thread. But I did not find this to
>be an issue - if object contains stuff that has thread affinity, it's
>not very eligible to be passed around threads anyhow.
****
Actually, most objects don't have anything that has "thread affinity", and the only known
characteristic of a CWnd* that has thread affinity is the HWND, because of the per-thread
handle map. BUt almost always we are passing around "interesting bits", e.g., HTML text
according to the OP. These are thread-neutral.
joe
****
>
>Goran.
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
COM inteface pointers have their own clearly-stated rules for thread behavior.

It is not clear that other pointers have similar limitations.
joe

On Sun, 2 May 2010 11:31:05 -0700 (PDT), Goran <goran.pusic(a)gmail.com> wrote:

>On May 2, 4:39�am, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>> Generally, you can pass any pointer across thereads. �However, there are some limitations
>> which are not always obvious.
>
>Attention, he stated that he wants to pass a COM interface pointer.
>That can't be passed to another thread. You kinda missed the boat with
>the explanation that follows.
>
>>
>> For example, both threads have to share the same heap and use the same allocator for
>> new/malloc delete/free. �This is the most common scenario, and therefore this requirement
>> is usually not mentioned or even noticed.
>>
>> But if the thread is in a DLL that has static linking of the CRT, you are doomed.
>>
>> Typically, what I would do is create a thread to fetch the data, and when the data is
>> received, use PostMessage to post a pointer to that data back to the main GUI thread; the
>> main GUI thread then uses the pointer in some reasonable fashion.
>>
>> The long explanation about the message pump is important and you really need to understand
>> that.
>
>
>Goran.
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm