Discussion:
CWinThread and WM_QUIT
(too old to reply)
Saul775
2006-11-16 17:23:02 UTC
Permalink
Hello, all:

I'm still getting accustomed to the idea of threads having a message queue,
but I'm trying to work with CWinThread because of the power of classes.

I have a class derived from CWinThread. It does background work for my main
thread. However, I'm trying to have it exit NICELY. By this, I mean I'd
like it to finish its last calculation before exiting. I've read many
articles and such on the Internet, but I have yet to see a consensus on how
to accomplish this.

Here is some sample code...

#define WM_BEGINCALC WM_APP + 0;

CMyThread::CMyThread()
{
this->m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
this->m_hOKToExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}

VOID CMyThread::OnBeginCalc(WPARAM wParam, LPARAM lParam)
{
BOOL bDone = FALSE;
while (!bDone)
{
if (WaitForSingleObject(this->m_hStopEvent, 0) == WAIT_OBJECT_0)
{
bDone = TRUE;
SetEvent(this->m_hOKToExitEvent);
}
else
{
... // Perform an epoch of calculations
}
}
}

I create my thread as follows...

CMyThread *pThread;
pThread = (CMyThread *)AfxBeginThread(RUNTIME_CLASS(CMyThread),
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->Initialize(...); // This just initializes some other variables I
need
pThread->ResumeThread();
pThread->BeginCalc(); // This does PostThreadMessage(WM_BEGINCALC, 0, 0)

Great! The thread is running!

However, now I want to stop the thread, but I want to stop it nicely. I've
tried capturing the WM_QUIT in PreProcessMessage(MSG *pMsg) as follows...

BOOL CDAQThread::PreTranslateMessage(MSG *pMsg)
{
if (pMsg->message == WM_QUIT)
{
SetEvent(this->m_hStopEvent); // This event stops the epoch
WaitForSingleObject(this->m_hOKToExitEvent, INFINITE);
}
return CWinThread::PreTranslateMessage(pMsg);
}

As such, I try stopping in the main thread as follows...

pThread->PostThreadMessage(WM_QUIT, 0, 0);
WaitForSingleObject(pThread->m_hThread, INFINITE);

Well, the thread never stops.

How can I make it that the thread will stop NICELY, but still finish it's
last epoch in the loop? Perhaps there is a better way to accomplish this?
Thank you, all.

Saul775
Dan Bloomquist
2006-11-16 17:42:32 UTC
Permalink
Post by Saul775
However, now I want to stop the thread, but I want to stop it nicely. I've
tried capturing the WM_QUIT in PreProcessMessage(MSG *pMsg) as follows...
Here is what I do.

someThread->PostThreadMessage( ID_THREAD_EXIT, 0, 0 );

and:
void CSomeThread::OnExit( WPARAM, LPARAM )
{
...
//clean it up
//very last thing
PostThreadMessage( WM_QUIT, 0, 0 );
}

This may be more elegant than trying to handle WM_QUIT for you.

Best, Dan.
Scott McPhillips [MVP]
2006-11-16 17:43:32 UTC
Permalink
Post by Saul775
BOOL CDAQThread::PreTranslateMessage(MSG *pMsg)
{
if (pMsg->message == WM_QUIT)
{
SetEvent(this->m_hStopEvent); // This event stops the epoch
WaitForSingleObject(this->m_hOKToExitEvent, INFINITE);
}
return CWinThread::PreTranslateMessage(pMsg);
}
As such, I try stopping in the main thread as follows...
pThread->PostThreadMessage(WM_QUIT, 0, 0);
WaitForSingleObject(pThread->m_hThread, INFINITE);
Well, the thread never stops.
How can I make it that the thread will stop NICELY, but still finish it's
last epoch in the loop? Perhaps there is a better way to accomplish this?
Thank you, all.
Saul775
The thread does not process messages while your epoch calculation is
executing. Instead of posting a message to the thread you can simply
set the m_hStopEvent from the main thread.

From your description, it seems that all your thread does is execute
the function OnBeginCalc. If that is the case then you can greatly
simplify things (and de-confuse yourself) by using a worker thread.
I.e., you don't appear to need a message processing thread. OnBeginCalc
would become the thread function.
--
Scott McPhillips [VC++ MVP]
Joseph M. Newcomer
2006-11-17 00:59:40 UTC
Permalink
You've made a simple problem hard. THere is no need to create an event, or poll it. A
simple 'volatile BOOL' variable which you can set to TRUE or FALSE to indicate a need to
stop would be sufficient. The event adds gratuitous complexity and tremendous overhead
without actually doing anything worthwhile.

A request to compute is queued up. It goes off and computes. If it finishes, it goes
back to the message pump and dequeues the next request. If it doesn't, the WM_QUIT will
never be dequeued and therefore never seen! Therefore the behavior you are seeing, that
the thread never stops, is in fact what is expected to happen.

Again, a simple boolean will suffice. To abort a computation, you set the "Stop" boolean
to TRUE. To shut down the thread, you set the Shutdown boolean to TRUE.

void CMyThread::OnBeginCalc(WPARAM, LPARAM)
{
if(Shutdown)
return; // discard this message
while(!Stop)
{
do computation
}
// we get here if the computation finishes or we set Stop
}

So setting the Stop flag will abort the current computation, and setting the shutdown flag
will stop all computations.

To shutdown,


Shutdown = TRUE;
Stop = TRUE;
thread->PostThreadMessage(WM_QUIT);

Note that if there are any computations already running, they will abort; if any requests
are still queued, they will be dequeued but not computed.
joe
Post by Saul775
I'm still getting accustomed to the idea of threads having a message queue,
but I'm trying to work with CWinThread because of the power of classes.
I have a class derived from CWinThread. It does background work for my main
thread. However, I'm trying to have it exit NICELY. By this, I mean I'd
like it to finish its last calculation before exiting. I've read many
articles and such on the Internet, but I have yet to see a consensus on how
to accomplish this.
Here is some sample code...
#define WM_BEGINCALC WM_APP + 0;
CMyThread::CMyThread()
{
this->m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
this->m_hOKToExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
VOID CMyThread::OnBeginCalc(WPARAM wParam, LPARAM lParam)
{
BOOL bDone = FALSE;
while (!bDone)
{
if (WaitForSingleObject(this->m_hStopEvent, 0) == WAIT_OBJECT_0)
{
bDone = TRUE;
SetEvent(this->m_hOKToExitEvent);
}
else
{
... // Perform an epoch of calculations
}
}
}
I create my thread as follows...
CMyThread *pThread;
pThread = (CMyThread *)AfxBeginThread(RUNTIME_CLASS(CMyThread),
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->Initialize(...); // This just initializes some other variables I
need
pThread->ResumeThread();
pThread->BeginCalc(); // This does PostThreadMessage(WM_BEGINCALC, 0, 0)
Great! The thread is running!
However, now I want to stop the thread, but I want to stop it nicely. I've
tried capturing the WM_QUIT in PreProcessMessage(MSG *pMsg) as follows...
BOOL CDAQThread::PreTranslateMessage(MSG *pMsg)
{
if (pMsg->message == WM_QUIT)
{
SetEvent(this->m_hStopEvent); // This event stops the epoch
WaitForSingleObject(this->m_hOKToExitEvent, INFINITE);
}
return CWinThread::PreTranslateMessage(pMsg);
}
As such, I try stopping in the main thread as follows...
pThread->PostThreadMessage(WM_QUIT, 0, 0);
WaitForSingleObject(pThread->m_hThread, INFINITE);
Well, the thread never stops.
How can I make it that the thread will stop NICELY, but still finish it's
last epoch in the loop? Perhaps there is a better way to accomplish this?
Thank you, all.
Saul775
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Loading...