"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
news:tg81h4t5l5eti5cqh5g6lcv0054tgrrcq2@4ax.com...
That's it. You have moved to an asynchrous world, and you can no longer
think of your
program as "closing the window while the thread is running". It isn't
supposed to happen.
So you make sure it doesn't.
I understand. I will make sure that I will strictly enforce this kind of
thinking in my code.
See my essay on worker threads on my MVP Tips site.
joe
On Tue, 4 Nov 2008 19:51:35 +0200, "vvf" <vvf@vvf.com> wrote:
Hi All,
Here is my scenario:
I have an MFC application. In one of the dialogs, I have a worker thread.
Here's how I start the thread:
m_pThread = AfxBeginThread((AFX_THREADPROC)LoadThread, this, 0, 0,
CREATE_SUSPENDED);
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();
The thread reads some rows from a database (SELECT * ..), and then
iterates
through the result set and sends the data rows one by one to the GUI to
update a GUI control:
for (int i = 0; i <= iUpperBound && (WaitForSingleObject(m_hQuitEvent,
0)
== WAIT_TIMEOUT); ++i)
{
/../
// Construct data, etc...
CData* pData = new CData; // pseudocode
PostMessage(UpdateMessage, (WPARAM)pData, ... ) // Update the
GUI
and delete pData
}
After the for loop is over, the thread function just finishes and this
thread ends. The m_hQuitEvent is there so that I can set it if I want to
abort the processing.
Here is how the message handler looks like:
LRESULT CWhateverDialog::OnUpdateMessage(WPARAM wParam, ...)
{
CData* pData = (CData*)wParam;
// update GUI control w/ pData information
delete pData;
return 0;
}
The problem is that when I close the dialog, even though I wait for the
thread to complete (WaitForSingleObject on its handle -
CWinThread::m_hThread), there are still some messages in the message queue
that are not yet processed and so I end up having some memory leaks
(because
the handler never gets a chance to be called to de-allocate the objects
allocated and postmessage'ed to the GUI.)
What is the correct way to handle this situation ?
Here is what I tried:
I have added two variables: m_iMessagesProcessed and m_iMessagesToProcess.
I
increment m_iMessagesToProcess in the thread, and I increment the
m_iMessagesProcessed in the message handler.
Then, I have another thread that basically does this:
while (m_iMessagesProcessed < m_iMessagesToProcess)
{
Sleep (50);
}
PostMessage(MSG_OkToQuit, ... )
I know that it is not a good idea to use Sleep but I have no idea what
else
to do here.. I just want to try again after a while and also allow other
threads to do their own thing. I could do a WaitForSingleObject on some
event that never gets signaled with a timeout of 50, but wouldn't that be
the exact same as sleep ? Anyway, 50 is just an arbitrary value; I know it
doesn't mean anything as Windows is not a realtime operating system... it
is
there just as a "let's try again 'later'"...
Anyway, in the message handler for MSG_OkToQuit, I basically do a
CDialog::OnOK() to dimiss it. However, even though I confirmed that
m_iMessagesProcessed is equal to m_iMessagesToProcess, I still get memory
leaks.
If, however, I wait for the thread to finish sending all the data, I do
not
get any memory leaks.
Therefore, it seems like I need to somehow make sure that I wait until all
the messages from the queue are processed but using a method different
than
the above which doesn't seem to work.
BTW, I know for sure that it is a problem with messages being queued
because
if I add a Sleep in the thread after the PostMessage, and I abort the
thread, I do not get the memory leaks. Therefore, it must be that by
adding
that Sleep, there is a greater chance for all the messages to be
processed.
Thanks and thank you for reading this long message,
vvf
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm