Prev: MFC Feature Pack App with full frame docking
Next: New control styles with imported VC6 app in VS2008
From: Joseph M. Newcomer on 2 May 2010 12:05 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 2 May 2010 14:31 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 2 May 2010 14:52 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 2 May 2010 18:25 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 2 May 2010 18:27 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
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 5 Prev: MFC Feature Pack App with full frame docking Next: New control styles with imported VC6 app in VS2008 |