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

AfxEndThread problem

787 views
Skip to first unread message

Frank

unread,
Oct 23, 2009, 6:16:10 AM10/23/09
to
Dear people,

I create a subthread of my main program by calling


AfxBeginThread(RUNTIME_CLASS(CMySubThread));


CMySubThread is derived from CWinThread. Eventually,
I'd like to terminate the thread. So I clean all variables,
buffer memory and the like, then call AfxEndThread(0)
from within a member function of CMySubThread.

The problem: This call seems to close the whole application,
it throws an exception in:

(code from AfxEndThread):

AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
CWinThread* pThread = pState->m_pCurrentWinThread;
if (pThread != NULL)
{
ASSERT_VALID(pThread);
ASSERT(pThread != AfxGetApp());


The last ASSERT causes the problem.

Now there are two questions:
- Why does the call try to close the whole app
instead of the thread?
- And how can I safely terminate the thread?


TIA!

Goran

unread,
Oct 23, 2009, 8:11:38 AM10/23/09
to
On Oct 23, 12:16 pm, Frank <j...@gmx.de> wrote:
> Now there are two questions:
> - Why does the call try to close the whole app
>   instead of the thread?
> - And how can I safely terminate the thread?

First things first: AfxTerminateThread is a shit function and is all
but unusable in normal C++ programming practices (same goes for
TerminateThread, _endthread and _endthreadex). DO NOT EVER CALL IT.
Why? Because it's a function that does not return. That means that
destructors of any stack objects you might have somewhere in the call
chain of the thread function will not be called. That also means that
any heap objects you should delete once your thread is done will not
be deleted. That is a tall order - e.g. one innocuous CString on the
stack and you start leaking memory.

Now for the answers

Q1:

AfxTerminateThread tries to close the app (it's better to say to
terminate the main thread) because you called it from a main thread.
You did not understand what AfxTerminateThread does.
AfxTerminateThread terminates a thread IN WHOSE CONTEXT IT HAS BEEN
CALLED.

There is a difference between a member function of your thread class
and an OS thread. You have to understand that distinction and call
functions accordingly. The fact that you are calling
AfxTerminateThread from a member function of your thread class DOES
NOT MEAN that it terminates OS thread that is in your code represented
by your instance of CWinThread. You called AfxTerminateThread from the
context of the main thread. That thread is in MFC represented by an
instance of a CWinApp. CWinApp should __NOT__ be terminated through
AfxTerminateThread (hence the ASSERT you got). That you called it from
a member function of your thread class DOES NOT MATTER.

Q2:

You must wait for your thread to end. THERE IS NO OTHER CORRECT WAY to
stop the thread, EXCEPT THIS:

1. have a flag, shared between "main" and the other thread.
2. when main thread decides that the other should stop, set a flag.
3. in the other thread, REPEATEDLY read that flag and stop when it
gets set
4. Use WaitForSingleObject or some other wait function to wait for the
thread to end.

Try to google out Doug Harrison's essay on how to work with MFC
threads and learn it by heart ;-).

Goran.

P.S. Flag can be a Windows event object. That way you can both check
if it's signaled (using WaitForSingleObject with a timeout of 0), and
wait on it using e.g. WaitForMultipleObjects if you also need to wait
on something else.

Best way I know for "checking the flag" is to throw an exception when
flag is set. I prefer to make that exception of type known only to the
thread function and nothing else, so that nothing except thread
function can catch it^^^. That way, there's no funny business: flag
set, once checked, causes thread function to exit (but, stack is
properly unwound).

^^^I know that catch(...) can catch it, but that is a total no-no in
the context of MFC, so that does not matter).

Scott McPhillips [MVP]

unread,
Oct 23, 2009, 10:09:19 AM10/23/09
to
"Frank" <je...@gmx.de> wrote in message
news:ba7f800a-fe53-4bb5...@o36g2000vbl.googlegroups.com...

> Dear people,
>
> I create a subthread of my main program by calling
>
>
> AfxBeginThread(RUNTIME_CLASS(CMySubThread));
>
>
> CMySubThread is derived from CWinThread. Eventually,
> I'd like to terminate the thread. So I clean all variables,
> buffer memory and the like, then call AfxEndThread(0)
> from within a member function of CMySubThread.

The thread must terminate itself. Just because you call from within a
member function of the thread class does not mean you are calling from the
thread. I.e., calling a function from the main thread means the function
executes in the main thread, no matter what class the function is part of.

The thread must call PostQuitMessage(0) to exit. Your main thread can
request the secondary thread to exit by posting a custom message to it or by
signaling an event that the thread monitors.

--
Scott McPhillips [VC++ MVP]

Frank

unread,
Oct 23, 2009, 10:28:32 AM10/23/09
to
Scott McPhillips wrote:

> The thread must terminate itself. Just because you call from within a
> member function of the thread class does not mean you are calling from the
> thread. I.e., calling a function from the main thread means the function
> executes in the main thread, no matter what class the function is part of.
>
> The thread must call PostQuitMessage(0) to exit. Your main thread can
> request the secondary thread to exit by posting a custom message to it or by
> signaling an event that the thread monitors.

I tried that: Had the main thread post a message
to the thread (PostThreadMessage), in the message handler

- call AfxEndThread
- PostQuitMessage(0)
- m_pMainWnd->PostMessage(WM_CLOSE, 0, 0)
- m_pMainWnd->PostMesage(WM_QUIT, 0, 0)

Everything closes the main program.

Do I have to do something about the message queue
of the subthread or something?

Seetharam

unread,
Oct 23, 2009, 10:58:55 AM10/23/09
to

Scott McPhillips [MVP]

unread,
Oct 23, 2009, 12:28:48 PM10/23/09
to
"Frank" <je...@gmx.de> wrote in message
news:99c68d59-60bc-44f1...@b18g2000vbl.googlegroups.com...

> I tried that: Had the main thread post a message
> to the thread (PostThreadMessage), in the message handler
>
> - call AfxEndThread
> - PostQuitMessage(0)
> - m_pMainWnd->PostMessage(WM_CLOSE, 0, 0)
> - m_pMainWnd->PostMesage(WM_QUIT, 0, 0)
>
> Everything closes the main program.
>
> Do I have to do something about the message queue
> of the subthread or something?

I don't understand your post. The correct approach is to do
PostQuitMessage(0) in the thread's message handler. You can find numerous
examples in the MFC samples or tutorials where this works. Or show your
code: You are leaving too much out of your explanation.

Goran

unread,
Oct 24, 2009, 2:21:32 AM10/24/09
to
Whoops, how wrong was I...

I __presumed__, apparently wrongly, that your thread is a worker
thread without a message loop (but with a thread function).

If you have a message loop, I will be presuming that you did something
like this to create the thread:

pMyThread = AfxBeginThread(..., CREATE_SUSPENDED/*ESSENTIAL*/, ...);
if (NULL = pMyThread) AfxThrowResourceException(); // Or something
else
// Note that AfxBeginThread might throw, too!
pMyThread->m_bAutoDelete = FALSE; // ESSENTIAL
VERIFY(pMyThread->ResumeThread() == 1);

... and that you are holding onto pMyThread correctly.

If your thread works through a message loop, then forget about a
shared termination flag. Use pMyThread->PostThreadMessage
(WM_SOMETHING). AFAIK, WM_SOMETHING can be WM_QUIT, but note that
WM_QUIT is a bit special (http://blogs.msdn.com/oldnewthing/archive/
2005/11/04/489028.aspx).

In a thread with a message loop, you should _not_ use a shared
"termination" flag. You should NOT use an exception to break out.

Even with a message loop, you should still NOT use AfxTerminateThread.

From the main thread, when you decide to stop pMyThread, you do:

VERIFY(pMyThread->PostThreadMessage(WM_SOMETHING, ...));
VERIFY(WaitForSingleObject(*pMyThread, INFINITE) == WAIT_OBJECT_0);
delete pMyThread; // "Official" MFC way is pMyThread->Delete(). That
is STUPID and I won't do it.

YOU have to make sure, through organization of your code^^^, that the
thread will pick the message up quickly enough so that you don't block
in WFSO for a long time, thereby having e.g. poor user experience
(there's NO magic trick, YOU have to do it).

^^^ "worker" threads with message loops are only good if all they do
are short bursts of activity caused by messages posted to them.

Goran.

Joseph M. Newcomer

unread,
Oct 24, 2009, 9:23:53 PM10/24/09
to
See below....

On Fri, 23 Oct 2009 03:16:10 -0700 (PDT), Frank <je...@gmx.de> wrote:

>Dear people,
>
>I create a subthread of my main program by calling
>
>
>AfxBeginThread(RUNTIME_CLASS(CMySubThread));
>
>
>CMySubThread is derived from CWinThread. Eventually,
>I'd like to terminate the thread. So I clean all variables,
>buffer memory and the like, then call AfxEndThread(0)
>from within a member function of CMySubThread.

****
Forget that you ever heard of this function. Do not ever call ExitThread as an API or any
of its thinly-disguised equivalences (such as AfxEndThread). Don't do it. Ever.

To terminate the thread, you return from the top-level thread function. That is the ONLY
correct way to terminate a thread. Any other technique opens you to all kinds of
potentially serious problems.
****


>
>The problem: This call seems to close the whole application,
>it throws an exception in:
>
>(code from AfxEndThread):
>
>AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
>CWinThread* pThread = pState->m_pCurrentWinThread;
>if (pThread != NULL)
> {
> ASSERT_VALID(pThread);
> ASSERT(pThread != AfxGetApp());
>
>
>The last ASSERT causes the problem.
>
>Now there are two questions:
>- Why does the call try to close the whole app
> instead of the thread?

***
Could it be because you are calling AfxEndThread from the main thread? You have give NO
context for where you call it. A classic blunder is

class CMyThread : public CWinThread {
public:
Stop() { AfxEndThread(0); }
};

class CMyView : public CView {
protected:
CMyThread * thread;
Stop() { thread->Stop(); }
};

which of course will stop your app, because while AfxExitThread will exit a thread, *it is
called in the context of your main GUI thread*, and therefore stops your app! This is
because it has meaning ONLY when called from the thread context itself. The above example
does not do that.

But don't ever use AfxExitThread. Exit from your top-level thread function. Since you
have shown no code at all, there is absolutely no way telll what you have done or how to
fix it.
****


>- And how can I safely terminate the thread?

****
If it is a UI thrread, PostQuitMessage(0) from within the thread itself.
joe
****
>
>
>TIA!
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer

unread,
Oct 24, 2009, 9:28:10 PM10/24/09
to
See below...

On Fri, 23 Oct 2009 07:28:32 -0700 (PDT), Frank <je...@gmx.de> wrote:

>Scott McPhillips wrote:
>
>> The thread must terminate itself. Just because you call from within a
>> member function of the thread class does not mean you are calling from the
>> thread. I.e., calling a function from the main thread means the function
>> executes in the main thread, no matter what class the function is part of.
>>
>> The thread must call PostQuitMessage(0) to exit. Your main thread can
>> request the secondary thread to exit by posting a custom message to it or by
>> signaling an event that the thread monitors.
>
>I tried that: Had the main thread post a message
>to the thread (PostThreadMessage), in the message handler
>
>- call AfxEndThread

****
Forget you ever heard of AfxEndThread. Never, ever, under any imaginable circumstances
should you call it. It does not exist. It is a figment of someone's imagination. Do
not, ever, ever, ever call it yourself.

Note that since you call AfxEndThread, none of the code below will ever be executed! So
it is pointless code.

I'm curious: why does stoppping the thread close the main app. And why would you ever,
EVER want to PostMessage a WM_QUIT to the main GUI thread (answer: because you have no
idea what you are doing!) This function will close the main GUI thread as well. But
worse still, it will stop the message pump even when there are still important messages to
be processed! The WM_CLOSE will close the main thread. STOP RIGHT THERE! DO NOT POST A
WM_QUIT TO THE MAIN MESSAGE LOOP, EVER!
joe

****


>- PostQuitMessage(0)
>- m_pMainWnd->PostMessage(WM_CLOSE, 0, 0)
>- m_pMainWnd->PostMesage(WM_QUIT, 0, 0)
>
>Everything closes the main program.

****
Are you surprised? You asked it to do so.
****


>
>Do I have to do something about the message queue
>of the subthread or something?

****
No. Once you PostQuitMessage to it, you are done.
joe
****

Frank

unread,
Oct 26, 2009, 4:05:04 AM10/26/09
to
Joseph M. Newcomer wrote:

> On Fri, 23 Oct 2009 07:28:32 -0700 (PDT), Frank <j...@gmx.de> wrote:

> >I tried that: Had the main thread post a message
> >to the thread (PostThreadMessage), in the message handler
>
> >- call AfxEndThread
>
> ****
> Forget you ever heard of AfxEndThread.  Never, ever, under any imaginable circumstances
> should you call it.  It does not exist.  It is a figment of someone's imagination.  Do
> not, ever, ever, ever call it yourself.
>
> Note that since you call AfxEndThread, none of the code below will ever be executed!  So
> it is pointless code.

Sorry Joseph, it seems to me that you believe I put all
those statements into the code. My bad. I tried all these
statements but only one at a time.

Joseph M. Newcomer

unread,
Oct 26, 2009, 8:24:01 AM10/26/09
to

****
That was not clear. So let's look at them, one at a time:

- call AfxEndThread
Always, without exception, the wrong thing to do
- PostQuitMessage(0)
Yes, this is how you stop your UI thread,
but you must be sure that no other message
can be posted after this one!


- m_pMainWnd->PostMessage(WM_CLOSE, 0, 0)

This tells your app to quit cleanly, except that
is apparently not what you wanted to do


- m_pMainWnd->PostMesage(WM_QUIT, 0, 0)

This kills your app, badly, and is always a mistake

0 new messages