Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Thread termination behavior

73 views
Skip to first unread message

Joseph M. Newcomer

unread,
Apr 3, 2009, 4:02:51 PM4/3/09
to
See below...
On Fri, 3 Apr 2009 10:50:01 -0700, BoHuang <BoH...@discussions.microsoft.com> wrote:

>I have thread A created by CreateThread() and supplied a 'run' function
>(lpStartAddress).
>
>After the 'run' function returns 0, when can I be sure thread A is properly
>terminated?
****
The simplest one is to do a WaitForSingleObject on the thread handle. This requires that
you mark the CWinThread object as not being deletable, and delete it yourself.
Alternatively, you duplicate the thread handle from the CWinThread-derived object and wait
for that.

You only need to wait if you have performed a shutdown request on the thread.

The problem with this is that you typically end up blocking the main GUI thread.

There are two possible solutions to this.

The simplest solution is to simply have the top-level thread function call PostMessage to
post a user-defined message to a specific window (usually passed in as part of the thread
function parameter, as an HWND, a CWnd*, or a pointer to a struct that contains an HWND or
a CWnd*). WHen you receive the message, you assume the thread has terminated.

Note that to make this work, you must not, under any imaginable circumstances, call
ExitThread or anything that wraps ExitThread (such as _endthread, _endthreadex,
AfxExitThread, etc.) in the execution of your thread. There is one, and only one, correct
way to terminate a thread, and that is to cause the thread to exit from its top-level
thread function.

The more elaborate solution is to have the receiver of that message do a
WaitForSingleObject on the thread handle of the thread until it actually finishes.
*****
>
>I ask because after the 'run' function terminates, thread A still lingers in
>Visual Studio's debugger. Except now its call stack is deep in ntdll.dll,
>hence I cannot examine what it is doing.
****
Do not confuse what the debugger is telling you with what is really happening. Debuggers
try to approximate the truth, but they are not always dead-on accurate. Note also that if
you fail to close the thread handle, the thread's stack will continue to exist, as well as
the kernel thread object. Normally, the handle is closed when the destructor for the
CWinThread object is executed.
****
>
>Thread A may or may not disappear soon from debugger window even as my main
>thread continues executation.
>
>I sometimes get error 170 (Resource in use) when calling wglMakeCurrent() in
>the main thread, and I suspect the lingering thread A is the culprit.
****
Without knowing the parameters to wglMakeCurrent, such as the HDC or the HGLRC, there's no
good way to tell what is going on. You would have to say how these are created, and how
the other thread (the one that is terminating) uses them, and how it releases them.
****
>
>Should I call CloseHandle() on thread A to close it immediately? If not,
>what can I expect from the OS?
****
This is normally handled by the destructor for the CWinThread object. So if you don't
delete the object, which is the default behavior when the thread terminates by leaving off
the top of the thread function, then you will have to delete it yourself (did you set
m_bAutoDelete to FALSE?)
****
>
>Also, when I step into code, I keep on getting into the disassembly window
>where it is all assembly code or a mix of assembly and C++ code. How can I
>turn that off?
****
Go To Source. If that doesn't work, I'm not sure what to do. Note that if you manage to
single-step into assembly code, you will stay in assembly code even when you end up back
in something it can give source for.
joe
****
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

AliR (VC++ MVP)

unread,
Apr 3, 2009, 3:03:38 PM4/3/09
to
I have never used CreateThead before, I have used AfxBeginThread.

But the doc for CreateThread says that you have to call CloseHandle on it
for it to be disposed. Now I don't know the details of when and where you
can call this function, I wonder if the thread function can call CloseHandle
before it returns. But like I said I

Why are you using CreateThead as supposed to AfxBeginThread?

AliR.


"BoHuang" <BoH...@discussions.microsoft.com> wrote in message
news:9513E734-EF91-4582...@microsoft.com...


>I have thread A created by CreateThread() and supplied a 'run' function
> (lpStartAddress).
>
> After the 'run' function returns 0, when can I be sure thread A is
> properly
> terminated?
>

> I ask because after the 'run' function terminates, thread A still lingers
> in
> Visual Studio's debugger. Except now its call stack is deep in ntdll.dll,
> hence I cannot examine what it is doing.
>

> Thread A may or may not disappear soon from debugger window even as my
> main
> thread continues executation.
>
> I sometimes get error 170 (Resource in use) when calling wglMakeCurrent()
> in
> the main thread, and I suspect the lingering thread A is the culprit.
>

> Should I call CloseHandle() on thread A to close it immediately? If not,
> what can I expect from the OS?
>

Joseph M. Newcomer

unread,
Apr 3, 2009, 4:24:21 PM4/3/09
to
I assumed that the reference was not to ::CreateThread, but to CWinThread::CreateThread.

You must not call ::CreateThread directly, you must call AfxBeginThread. The thread
handle is the m_hThread member of the CWinThread class. CWinThread::~CWinThread closes
the handle, and if you terminate the thread by returning off its top-level thread
function, then if you have not changed the value of CWinThread::m_bAutoDelete from its
default value of TRUE, then the CWinThread object is implicitly deleted which will then
close the handle.

Calling ::CreateThread directly in an MFC program is an error.
joe

Doug Harrison [MVP]

unread,
Apr 3, 2009, 3:38:34 PM4/3/09
to
On Fri, 3 Apr 2009 10:50:01 -0700, BoHuang
<BoH...@discussions.microsoft.com> wrote:

>I have thread A created by CreateThread() and supplied a 'run' function
>(lpStartAddress).
>
>After the 'run' function returns 0, when can I be sure thread A is properly
>terminated?
>
>I ask because after the 'run' function terminates, thread A still lingers in
>Visual Studio's debugger. Except now its call stack is deep in ntdll.dll,
>hence I cannot examine what it is doing.
>
>Thread A may or may not disappear soon from debugger window even as my main
>thread continues executation.
>
>I sometimes get error 170 (Resource in use) when calling wglMakeCurrent() in
>the main thread, and I suspect the lingering thread A is the culprit.
>
>Should I call CloseHandle() on thread A to close it immediately? If not,
>what can I expect from the OS?

Closing a thread handle does not terminate the thread. However, until all
handles are closed, the OS does maintain some info about the thread, even
after the thread has terminated. When the process is exited, secondary
threads continue to run until they are forcibly terminated by the OS when
the process calls ExitProcess (the unbridled running while the process is
shutting down being a very bad thing to allow), and handles are closed.

As for detecting thread termination, a thread continues to run while its
handle remains non-signalled. Therefore, you need to use a wait function
such as WaitForSingleObject. You can also use GetThreadExitCode; if that
function returns STILL_ACTIVE, the thread is still running.

In an MFC program, you need to use CWinThread. See this page for some tips
on avoiding its design problems and info on "joining" with your secondary
threads:

http://members.cox.net/doug_web/threads.htm

Each question builds on the previous one, so the whole thing is relevant.

--
Doug Harrison
Visual C++ MVP

Joseph M. Newcomer

unread,
Apr 3, 2009, 9:04:08 PM4/3/09
to
But using GetThreadExitCode suggests this is a reasonable way to determine thread
termination. Polling is not really best-practice (I've all too often seen people do a
GetThreadExitCode loop in the main GUI thread while they wait for a thread to finish).

It also doesn't help that the value STILL_ACTIVE is a potentially valid value for a thread
to use as a completion code.
joe

0 new messages