Roland wrote:
>Hello There
>I am using an User interface thread. I'll just explain my
>functionality and then move towards problem.
> When the document is navigated completelly (WebBrowser),I am
>starting a user interface thread and storing thread pointer in
>m_pCurrentThread. When new document is navigated again ,I want to stop
>the previous thread and start the new thread again. So I maintained
>the 2 thread (previos and current ) in two varaibles,like this
>void OnDocumnetComplete()
>{
> // m_pPrevThread and m_pCurrThread are NULL initially (in
>constructor)
> if (m_pPrevThread != NULL )
> {
> // If Previous Thread exists Then forse it to terminate
> m_pPrevThread->m_bAbort=TRUE;
> m_pPrevThread->PostThreadMessage(UWM_TERMINATE_THREAD,0,0);
> }
> // New thread is created
> m_pCurrThread=(CDiscoveryThread*)AfxBeginThread(RUNTIME_CLASS
>(CDiscoveryThread),THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
> if (m_pCurrThread)
> {
> m_pCurrThread->m_pParent=this;
> m_pCurrThread->ResumeThread();
> m_pPrevThread=m_pCurrThread;
> }
>}
>But sometimes application is crashing arbitrally at
> m_pThread->PostThreadMessgae(...);
>when I saw the value of m_pPrevThread , it was valid but the handle of
>thread was NULL. Can you tell me what would the possible reason of
>this ? How can I get rid off this problem ? Can you suggest any
>another idea to do this ?
It's probably crashing because you're allowing the default auto-delete
behavior. Below are some excerpts from previous messages I've written
about this.
***** About safely using CWinThread:
To safely use CWinThread, you must start the thread suspended and set the
CWinThread object's m_bAutoDelete member to false or DuplicateHandle a copy
of its m_hThread member. Only then should you resume the thread. This avoids
the race condition resulting from the default auto-delete behavior, allowing
you to wait on the thread handle. It's even worse than that. According to
the current WaitForSingleObject documentation, it's undefined for a handle
to be closed while you're waiting on it. Thus, all code which waits on a
CWinThread m_hThread member while the CWinThread auto-deletes itself is
undefined. If you set m_bAutoDelete to false, you assume the responsibility
for deleting the CWinThread, while if you dup m_hThread, you will have to
close the duped handle when you're done with it. I find it easier to change
m_bAutoDelete.
***** About why you should explicitly join with your threads before exiting
your app:
In general, it's a bad idea to allow secondary threads to continue executing
as the application is shutting down, static duration objects are being
destroyed, the CRT is being taken down, etc, until the CRT finally calls
ExitProcess and kills them all, assuming the secondary threads haven't
deadlocked with the CRT shutting down in the primary thread or crashed in
the meantime, say, due to objects they're using being destroyed. To avoid
this and achieve an orderly shutdown, you have to join with all your threads
before exiting your app, and that means being able to wait on their handles.
But you can't wait on their handles if they auto-delete themselves, because
according to MSDN, it's undefined to close a handle being used in a Wait
function, and it's the secondary thread that closes the CWinThread handle
before auto-deleting and terminating, the latter being the thing which would
cause the handle to become signaled, if only it hadn't been closed already!
This whole auto-deletion concept as applied to threads is pretty much a bad
idea, with limited utility.
***** About using a quit-event instead of bool "quit" variables (assumes a
worker thread, though, or a message loop based on
MsgWaitForMultipleObjects):
Events are much more flexible. They support polling with
WaitForSingleObject, but you can also use them in WaitForMultipleObjects.
This comes in handy when you'd like to wait forever on some other object.
You can't use WaitForSingleObject(INFINITE), because you'd miss thread exit
requests that are made before the object you're waiting on is signaled. Some
people solve this problem by waiting a second or two and polling their
"quit" variable in a loop. But if you use a quit-event and store it as the
first object in the WFMO handle array, you can wait forever, which means you
wait more efficiently, and you normally don't need the "while (running)"
loop. My code tends to look like this:
// WaitAny is overloaded on up to 5 WaitableHandles, and it waits forever.
// quitEvent is an Event object, and Event is derived from WaitableHandle.
switch (WaitAny(quitEvent, other WaitableHandles))
{
case WAIT_OBJECT_0 :
clean up and exit;
...other cases
}
***** So, assuming you can arrange for your thread to exit in a timely
matter, I'd replace:
m_pPrevThread->m_bAbort=TRUE;
m_pPrevThread->PostThreadMessage(UWM_TERMINATE_THREAD,0,0);
with:
SetEvent(m_pPrevThread->quitEvent);
WaitForSingleObject(m_pPrevThread->m_hThread, INFINITE);
delete m_pPrevThread;
m_pPrevThread = 0;
If you can't arrange for your thread to exit quickly, or if there's any
possibility of indefinite waiting (including deadlock) when you call WFSO,
and you can't fix the problem, you could have your thread post a message
back to the "owner" thread right before it terminates. Then the owner could
join with the thread before deleting the thread object. See this KB article
for some notes on using PostThreadMessage:
PRB: PostThreadMessage Messages Lost When Posted to UI Thread
http://support.microsoft.com/default.aspx?scid=kb;en-us;183116
All that said, is there any reason you have to kill the original thread and
start a new one? Is there any reason you can't find a way to reuse the
original thread?
--
Doug Harrison
Microsoft MVP - Visual C++