From: Hector Santos on
Joseph M. Newcomer wrote:

> COM inteface pointers have their own clearly-stated rules for thread behavior.
>
> It is not clear that other pointers have similar limitations.
> joe
>


But nice to know what the OP was actually doing. Sounds to me that he
was walking/access the object DOM.

If this is the case, he has access it to with the IWebBrowser2
instance member in his window, by passing it to a thread:

AfxBeginThread(WebDomThreadProc,&m_web);

The docs for DocumentComplete() says pDisp is the interface for the
Window, so it might be the same as m_web->get_Document(). Maybe not.

Either way, however he also stated the page can change, so I suspect
that the collections will be altered as he traverses the DOM.

I just explored this, and it indeed worked and by adding a small delay
in the collection traversal, I changed the page and indeed the last
collection no longer valid.

If he needs to keep the same collection, then he needs to place the
web browser from changing pages.

Either that or he makes a copy of the collection before starting the
thread and the thread works with the copied DOM collection.

Is there a Clone Dom method?

--
HLS
From: Goran on
On May 3, 12:25 am, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> See below...
>
>
>
> On Sun, 2 May 2010 11:52:02 -0700 (PDT), Goran <goran.pu...(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.

Yes, I was thinking about errors that arise due to not respecting
that. It's not really lifetime of the CWnd*, it's more the lifetime of
HWND that poses problems. I guess that one can say: the code in the
thread must either have no expectations WRT CWnd/HWND lifetime, and
deal with the consequences (my approach with shared/weak ptr), either
what you say. I found that, when I need to deal with views/frames, "no
expectations" approach is easier, because user actions, MFC and system
control lifetime of CWnd/HWNDs. For e.g. progress dialogs etc, your
approach is easier.

>
> Passing an HWND is more conservative, but leads to a whole NEW set of problems, which are
> actually more dangerous to the uninitiated.

What the problems are (honest question)? I know of two: one still
can't use SendMessage (that has thread affinity), and HWND might get
reused. Is there more?

> ****>* 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
> ****

Yes, of course, same heap is required. As you stated before, that's
most often the case, so it's not a big deal.

Goran.
From: nexo on
On May 3, 12:12 pm, Goran <goran.pu...(a)gmail.com> wrote:
> On May 3, 12:25 am, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>
>
>
> > See below...
>
> > On Sun, 2 May 2010 11:52:02 -0700 (PDT), Goran <goran.pu...(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.
>
> Yes, I was thinking about errors that arise due to not respecting
> that. It's not really lifetime of the CWnd*, it's more the lifetime of
> HWND that poses problems. I guess that one can say: the code in the
> thread must either have no expectations WRT CWnd/HWND lifetime, and
> deal with the consequences (my approach with shared/weak ptr), either
> what you say. I found that, when I need to deal with views/frames, "no
> expectations" approach is easier, because user actions, MFC and system
> control lifetime of CWnd/HWNDs. For e.g. progress dialogs etc, your
> approach is easier.
>
>
>
> > Passing an HWND is more conservative, but leads to a whole NEW set of problems, which are
> > actually more dangerous to the uninitiated.
>
> What the problems are (honest question)? I know of two: one still
> can't use SendMessage (that has thread affinity), and HWND might get
> reused. Is there more?
>
>
>
> > ****>* 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
> > ****
>
> Yes, of course, same heap is required. As you stated before, that's
> most often the case, so it's not a big deal.
>
> Goran.

Well , This has nothing to do with COM threading rules or models (STA/
MTA are the used words..)
And I tried to pass the pointer to another thread started from
OnDocumentComplete and it worked fine without any problem at all.

And while doing this I remembered doing the same in a shell extension
that i wrote once( in ATL )
And I know i posted here in MFC community .. but i am creating this
BHO in C# !!
and i was able to pass the object pDisp easily and safely to the other
thread .

PS:- dont know what is happening to microsoft.public.vc.mfc on my
side, i posted several messages that are not visible here and nor does
are your messages visible on the microsoft's site(to me?) ... so
finally got in here at google.

Thanks to everyone :)
Thanks.
From: Joseph M. Newcomer on
See below...
On Mon, 3 May 2010 00:12:35 -0700 (PDT), Goran <goran.pusic(a)gmail.com> wrote:

>On May 3, 12:25�am, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>> See below...
>>
>>
>>
>> On Sun, 2 May 2010 11:52:02 -0700 (PDT), Goran <goran.pu...(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.
>
>Yes, I was thinking about errors that arise due to not respecting
>that. It's not really lifetime of the CWnd*, it's more the lifetime of
>HWND that poses problems. I guess that one can say: the code in the
>thread must either have no expectations WRT CWnd/HWND lifetime, and
>deal with the consequences (my approach with shared/weak ptr), either
>what you say. I found that, when I need to deal with views/frames, "no
>expectations" approach is easier, because user actions, MFC and system
>control lifetime of CWnd/HWNDs. For e.g. progress dialogs etc, your
>approach is easier.
****
If you pass a CWnd* across a thread boundary, you must not allow the CWnd object to be
deleted until the thread is done using it. This is critical, because what will happen is
the thread could end up accessing free storage which might actually be reallocated for
some other object.

The HWND in this case is less critical, because if you manage to destroy the HWND without
deleting the CWnd *, any methods you invoke on the HWND (e.g., PostMessage) will
assert-fail. In a release version, the data posted will result, typically, in a storage
leak, because the receiving window isn't there. Serious, but not really fatal (until you
run out of heap!)

But if you pass the HWND, the common failure mode is


class CMyView : public CView {
protected:
static UINT handler(LPVOID p);
..
}

AfxBeginThread(handler, this);

/*static */ UINT CMyView::handler(LPVOID p)
{
CMyView * view = (CMyView *)p;

// this works correctly
}

But I've seen people who are told "You must pass the HWND because I once read a document
that said passing CWnd * is a Bad Idea" do the following

AfxBeginThread(handler, (LPVOID)m_hWnd);

/* static */ UINT CMyView::handler(LPVOID p)
{
CMyVIew * view = (CMyView*)CWnd::FromHandle((HWND)p);

}

OK, here's a Quickie Quiz: What's wrong with the above code? And why is it a Really
Really Bad Idea?

This is one of those subtleties of where MFC Meets System Programming that I talk about in
my course.
****
>
>>
>> Passing an HWND is more conservative, but leads to a whole NEW set of problems, which are
>> actually more dangerous to the uninitiated.
>
>What the problems are (honest question)? I know of two: one still
>can't use SendMessage (that has thread affinity), and HWND might get
>reused. Is there more?
****
Yes. And if you don't know the answer to the above Quickie Quiz, I'll give the solution
in a subsequent post. But that failure (or more than one failure, as it turns out) is a
key problem with passing an HWND across.

And while both of your problems are issues (and it isn't a "thread affinity" issue with
HWND as such, but the complex synchronization required to get the SendMessage handled in
the context of the receiving thread, and HWND value reuse, although a real issue, is a
rare problem; the two deeply serious problems are far worse than either of the above), one
of the key issues (and yet another issue) is the lifetime of the CWnd* and the fact that
you MUST NOT allow it to be deleted while the thread thinks it has a valid pointer! This
is a pointer-sharing issue. And using shared_ptr solves only the pointer problem, not the
HWND problem, so essentially the rule is: he who owns it must delete it, and shared_ptr
allows the (to me, incorrect) passing of ownership to the thread, which shouldn't EVER own
the CWnd* object (only the creating thread should own it!) So from my viewpoint,
shared_ptr is NOT the correct solution here because it causes a failure in ownership
rights, incorrectly transferring the ownership.

The problem is much more complex, and the solutions are also complex, but necessary. Only
the UI thread that creates the object is permitted to destroy it, and it must not destroy
it if the object is in use in any thread. Therefore, a positive protocol is required
wherein every thread who might share access to the CWnd* will inform the owner when they
have finished, and only the owner is allowed to actually delete the object.
****
>
>> ****>* 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
>> ****
>
>Yes, of course, same heap is required. As you stated before, that's
>most often the case, so it's not a big deal.
****
Note that a lot of STL objects have an allocator reference that goes with them, and if so,
this would be a way to deal with the multiple-heap problem.
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: Hector Santos on
Joseph M. Newcomer wrote:

> ****
> If you pass a CWnd* across a thread boundary, you must not allow the CWnd object to be
> deleted until the thread is done using it. This is critical, because what will happen is
> the thread could end up accessing free storage which might actually be reallocated for
> some other object.


Isn't that general true as a rule of thumb of passing a pointer to a
thread that could be become invalid outside the thread?

What is CWnd* or HWND for the matter special in this regard?

Its a simple owner vs non-owner or z-order concept : if you didn't
create it, you shouldn't delete it unless it was specifically creates
for the thread to delete.

Its also relates to cross process or dll boundaries, it is not
recommended to create in one boundary and delete in another.

> But if you pass the HWND, the common failure mode is
>
>
> class CMyView : public CView {
> protected:
> static UINT handler(LPVOID p);
> ..
> }
>
> AfxBeginThread(handler, this);
>
> /*static */ UINT CMyView::handler(LPVOID p)
> {
> CMyView * view = (CMyView *)p;
>
> // this works correctly
> }
>
> But I've seen people who are told "You must pass the HWND because I once read a document
> that said passing CWnd * is a Bad Idea" do the following
>
> AfxBeginThread(handler, (LPVOID)m_hWnd);
>
> /* static */ UINT CMyView::handler(LPVOID p)
> {
> CMyVIew * view = (CMyView*)CWnd::FromHandle((HWND)p);
>
> }
>
> OK, here's a Quickie Quiz: What's wrong with the above code? And why is it a Really
> Really Bad Idea?


Thats easy, two things:

1) you are asking for something that is managed in some global table
(a map in this case)

2) if its not found, a new one is created, and the thread will not
know that fact in order to delete it.

This is old material, but MFC historically used TLS to maintain its
recording of Windows and handles per thread and across boundaries
(i.e. a MFC DLL) that was problematic, especially for use MFC based
objects, i.e, CString So in MFC 4.0, it uses a set of template
classes to wrap process level data. For example, this is a little
known trick and it works extremely work:

struct CMyProcessData : public CNoTrackObject;
{
CString s;
}
struct CMyThreadData : public CNoTrackObject;
{
CString s;
}
CProcessLocal<CMyProcessData> MyProcessData;
CThreadLocal<CMyThreadData> MyThreadData;

void SetProcessString(LPCTSTR lpsz) { MyProcssData->s = lpsz; }
void SetThreadString(LPCTSTR lpsz) { MyThreadData->s = lpsz; }
CString GetProcessString() { return MyProcssData->s; }
CString GetThreadString() { return MyThreadData->s; }

When you start a thread, it will automatically get its own instance of
CMyThreadData. I use this for a few dlls that creates threads and it
allows me to maintain MFC safe process and thread state information
when using MFC objects.

This is documented in a MSDN Tech Note:

TN058: MFC Module State Implementation.
http://msdn.microsoft.com/en-us/library/ft1t4bbc(VS.80).aspx

> This is one of those subtleties of where MFC Meets System Programming that I talk about in
> my course.


(RAISING HAND!)

Isn't it better to as a general practice of pointer usage to
understand how memory is used rather than making everything else fit
under MFC?

Understanding MFC is important, but following basic concepts of
z-order programming inherently solves 99.99% (if not 100%) of the
design questions to a point it doesn't become a question at all.

One of the problems (and goran we had this discussion before) with
using higher layer tools, is that it increases the understanding
requirements that can be become very subtle and quite often requires a
DEEP understanding of the higher layer wrappings itself missing
critical points of the basic underlining framework.

Example, this is something I'm currently working on with touches based
with this idea of z-order and pointer ownerships and usage;
Asynchronous RPC using a I/O completion port notification type. There
is no MSDN example only a Event based notification type. Googling
shows no results and the closest one is so complex with an extremely
rich library that is dependent on so many other things that not even
downloading the source and reviewing the code was difficult to see
what is the basic framework to get it done.

This required rolling up the sleeve and trying various ideas using the
"raw" IOCP and ASYNC RPC API functions, re-reading the MSDN docs as
you see results until you finally understand whats going on and get
the layout right. I just now at this moment reached that point and
took a timeout to read the MFC forum.

The irony is now I will be wrapping it with my own classes to make it
easy. I can only do that one you understand the basics.

--
HLS