Re: checking if thread has ended
This is a multi-part message in MIME format.
--------------050102010909050705070208
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Doug Harrison [MVP] wrote:
On Tue, 29 Jul 2008 13:14:39 +0530, Ashutosh <smbs-msdn@nospam.nospam>
wrote:
Joseph M. Newcomer wrote:
See below...
On Tue, 29 Jul 2008 04:46:00 +0530, Ashutosh <smbs-msdn@nospam.nospam> wrote:
Hi,
I am creating a background thread using AfxBeginThread in suspended state, then setting the auto delete member to false then resuming the thread.
***
Yes, this is the standard way to do it.
****
Now from the main thread when I call WaitForSingleObject with the thread handle and infinite timeout, it doesn't return even after the thread procedure has ended/returned
***
This would be a serious design error. You should not block the main thread "waiting" for
a secondary thread. Instead, have the thread PostMessage a notification to the main GUI
thread that says "I am done". You don't need to WFSO at all. For that matter, there is
probably no reason to set m_bAutoDelete to FALSE since there is no reason you should have
to care about whether or not the object is deleted.
*****
So, how do I check if the thread has terminated? I can use some variable to indicate that, but is there a way to find this using the CWinThread object returned?
****
Since you have not shown the WFSO code, so it is hard to tell what might have gone wrong,
but it should certainly continue after the thread terminates. HOWEVER, if you attempted
to manipulate any GUI object in the main thread, then the secondary thread will hang
forever because the main thread is blocked, and therefore the WFSO will never terminate
because the secondary thread is blocked by the WFSO.
So
(a) make sure that you DO NOT touch ANY control whatsoever from your thread
(b) Get rid of the WFSO entirely and the setting of m_bAutoDelete, and replace them with a
PostMessage to the main GUI thread.
Read my essays on threading on my MVP Tips site.
joe
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Thanks Doug/Joseph for your comment!!!
I was calling WFSO on the WM_CLOSE message before the CDIalog::OnClose
(make sense) and for other communications I was/am using
PostMessage/SendMessage only!!! It was in the WM_CLOSE message handler
the code didn't return from WFSO. I am doing this just to make sure that
the background thread is not killed when the main window/thread is
destroyed.
Isn't this the correct way??
The code is like this
this->ShowWindow(SW_HIDE);
if(pWorkerThread)
{
WaitForSingleObject(pWorkerThread->m_hThread, INFINITE);
}
CDialog::OnClose();
If the thread will terminate quickly, you don't need the ShowWindow call.
If it isn't terminating quickly, why isn't it? Have you told it to close?
In the web page I linked to, Q4 reads:
http://members.cox.net/doug_web/threads.htm#Q4
<q>
Q4. How can I ask a thread to exit and wait for it, anyway?
A. Assuming you've read everything above, the following should make sense:
// The variable pThread points to a CMyThread that was started
// suspended, and whose m_bAutoDelete member was set to false,
// as described in Q1. The class CMyThread was derived from
// CWinThread and contains an event variable called quitEvent.
SetEvent(pThread->quitEvent);
WaitForSingleObject(pThread->m_hThread, INFINITE);
delete pThread;
This works great if you've designed the secondary thread to exit quickly
once quitEvent has been set. However, the waiting thread cannot proceed
until the other thread has terminated, so this sequence should not be used
unless you can guarantee a timely exit, or it's acceptable to wait
indefinitely. For an MFC program's main GUI thread, it's typically not
acceptable to wait indefinitely in WaitForSingleObject, because it prevents
the program from processing messages, which makes it unresponsive to user
input, redraw requests, and so forth.
</q>
I don't see any code corresponding to my SetEvent call.
If your secondary thread is using SendMessage or calling any SendMessage
wrapper (e.g. CWnd::SetWindowText) to a window belonging to the main
thread, which is stuck in WFSO, you have a deadlock. If you are creating a
window in the secondary thread whose parent was created in the primary
thread, you may have a deadlock, since interthread child/parent
communication cannot proceed while the primary thread is stuck in WFSO. The
only way to avoid this sort of deadlock is for the primary thread to
continue running a message loop of some sort, since pending interthread
sent messages are dispatched when the target thread calls GetMessage,
MsgWaitForMultipleObjects, and other message retrieval functions, or
(perhaps surprisingly) when the target thread calls SendMessage. But it's
best to avoid this sort of dependency entirely and not create windows in
your secondary threads.
Thanks Joseph/Doug for your wonderful explanation :-)
My code had a deadlock due to SendMessage!!
--------------050102010909050705070208
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
<br>
<br>
Doug Harrison [MVP] wrote:
<blockquote cite="mid:l5au84pkmd1a1jaa9s16udpfmoqcjtn4k8@4ax.com"
type="cite">
<pre wrap="">On Tue, 29 Jul 2008 13:14:39 +0530, Ashutosh <a class="moz-txt-link-rfc2396E" href="mailto:smbs-msdn@nospam.nospam"><smbs-msdn@nospam.nospam></a>
wrote:
</pre>
<blockquote type="cite">
<pre wrap="">
Joseph M. Newcomer wrote:
</pre>
<blockquote type="cite">
<pre wrap="">See below...
On Tue, 29 Jul 2008 04:46:00 +0530, Ashutosh <a class="moz-txt-link-rfc2396E" href="mailto:smbs-msdn@nospam.nospam"><smbs-msdn@nospam.nospam></a> wrote:
</pre>
<blockquote type="cite">
<pre wrap="">Hi,
I am creating a background thread using AfxBeginThread in suspended state, then setting the auto delete member to false then resuming the thread.
</pre>
</blockquote>
<pre wrap="">***
Yes, this is the standard way to do it.
****
</pre>
<blockquote type="cite">
<pre wrap="">Now from the main thread when I call WaitForSingleObject with the thread handle and infinite timeout, it doesn't return even after the thread procedure has ended/returned
</pre>
</blockquote>
<pre wrap="">***
This would be a serious design error. You should not block the main thread "waiting" for
a secondary thread. Instead, have the thread PostMessage a notification to the main GUI
thread that says "I am done". You don't need to WFSO at all. For that matter, there is
probably no reason to set m_bAutoDelete to FALSE since there is no reason you should have
to care about whether or not the object is deleted.
*****
</pre>
<blockquote type="cite">
<pre wrap="">So, how do I check if the thread has terminated? I can use some variable to indicate that, but is there a way to find this using the CWinThread object returned?
</pre>
</blockquote>
<pre wrap="">****
Since you have not shown the WFSO code, so it is hard to tell what might have gone wrong,
but it should certainly continue after the thread terminates. HOWEVER, if you attempted
to manipulate any GUI object in the main thread, then the secondary thread will hang
forever because the main thread is blocked, and therefore the WFSO will never terminate
because the secondary thread is blocked by the WFSO.
So
(a) make sure that you DO NOT touch ANY control whatsoever from your thread
(b) Get rid of the WFSO entirely and the setting of m_bAutoDelete, and replace them with a
PostMessage to the main GUI thread.
Read my essays on threading on my MVP Tips site.
joe
Joseph M. Newcomer [MVP]
email: <a class="moz-txt-link-abbreviated" href="mailto:newcomer@flounder.com">newcomer@flounder.com</a>
Web: <a class="moz-txt-link-freetext" href="http://www.flounder.com">http://www.flounder.com</a>
MVP Tips: <a class="moz-txt-link-freetext" href="http://www.flounder.com/mvp_tips.htm">http://www.flounder.com/mvp_tips.htm</a>
</pre>
</blockquote>
<pre wrap="">Thanks Doug/Joseph for your comment!!!
I was calling WFSO on the WM_CLOSE message before the CDIalog::OnClose
(make sense) and for other communications I was/am using
PostMessage/SendMessage only!!! It was in the WM_CLOSE message handler
the code didn't return from WFSO. I am doing this just to make sure that
the background thread is not killed when the main window/thread is
destroyed.
Isn't this the correct way??
The code is like this
this->ShowWindow(SW_HIDE);
if(pWorkerThread)
{
WaitForSingleObject(pWorkerThread->m_hThread, INFINITE);
}
CDialog::OnClose();
</pre>
</blockquote>
<pre wrap=""><!---->
If the thread will terminate quickly, you don't need the ShowWindow call.
If it isn't terminating quickly, why isn't it? Have you told it to close?
In the web page I linked to, Q4 reads:
<a class="moz-txt-link-freetext" href="http://members.cox.net/doug_web/threads.htm#Q4">http://members.cox.net/doug_web/threads.htm#Q4</a>
<q>
Q4. How can I ask a thread to exit and wait for it, anyway?
A. Assuming you've read everything above, the following should make sense:
// The variable pThread points to a CMyThread that was started
// suspended, and whose m_bAutoDelete member was set to false,
// as described in Q1. The class CMyThread was derived from
// CWinThread and contains an event variable called quitEvent.
SetEvent(pThread->quitEvent);
WaitForSingleObject(pThread->m_hThread, INFINITE);
delete pThread;
This works great if you've designed the secondary thread to exit quickly
once quitEvent has been set. However, the waiting thread cannot proceed
until the other thread has terminated, so this sequence should not be used
unless you can guarantee a timely exit, or it's acceptable to wait
indefinitely. For an MFC program's main GUI thread, it's typically not
acceptable to wait indefinitely in WaitForSingleObject, because it prevents
the program from processing messages, which makes it unresponsive to user
input, redraw requests, and so forth.
</q>
I don't see any code corresponding to my SetEvent call.
If your secondary thread is using SendMessage or calling any SendMessage
wrapper (e.g. CWnd::SetWindowText) to a window belonging to the main
thread, which is stuck in WFSO, you have a deadlock. If you are creating a
window in the secondary thread whose parent was created in the primary
thread, you may have a deadlock, since interthread child/parent
communication cannot proceed while the primary thread is stuck in WFSO. The
only way to avoid this sort of deadlock is for the primary thread to
continue running a message loop of some sort, since pending interthread
sent messages are dispatched when the target thread calls GetMessage,
MsgWaitForMultipleObjects, and other message retrieval functions, or
(perhaps surprisingly) when the target thread calls SendMessage. But it's
best to avoid this sort of dependency entirely and not create windows in
your secondary threads.
</pre>
</blockquote>
Thanks Joseph/Doug for your wonderful explanation <span
class="moz-smiley-s1"><span> :-) </span></span><br>
<br>
My code had a deadlock due to SendMessage!!<br>
</body>
</html>
--------------050102010909050705070208--