MFC and Worker Thread issue
I have a worker thread to do some heavy background job. From the frontend GUI
if user says cancel I want to wait till worker thread has completed one round
of job and that thread has exited. But It appears like once user says cancel,
OnDestroy is called followed by the destructor and the thread never seem to
have got a chance.
Here is the pseudo code, can you please help me point out the problem ?
Thanks a lot in advance.
CMyDlg * p_Dlg;
Class CMyDlg : public CDialog
{
public:
CMyDlg(CWnd* pParent = NULL); // standard constructor
~CMyDlg();
CWinThread* m_pMyWorkerThread;
HANDLE m_hEventStopMyWorkerThread;
HANDLE m_hEventMyWorkerThreadKilled;
BOOLEAN m_isDialogClosing;
protected:
static UINT WorkerFunction(LPVOID pParam);
virtual BOOL OnInitDialog();
afx_msg void OnDestroy();
void OnWorkButton();
}
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)
{
// Use the following events for thread notification.
m_hEventStopMyWorkerThread = CreateEvent(NULL, FALSE, FALSE, NULL); //
auto reset, initially reset
m_hEventMyWorkerThreadKilled = CreateEvent(NULL, FALSE, FALSE, NULL); //
auto reset, initially reset
m_isDialogClosing = FALSE;
m_pMyWorkerThread = NULL;
p_Dlg = this;
}
CMyDlg::~CMyDlg()
{
DWORD dwExitCode;
if (m_pMyWorkerThread != NULL &&
GetExitCodeThread(m_pMyWorkerThread->m_hThread, &dwExitCode) &&
dwExitCode == STILL_ACTIVE)
{
// Set flag to indicate the dialog is closing. This is
// used to distinguish between stopping the worker thread due to
// closing the dialog versus worker thread actually completing.
m_isDialogClosing = TRUE;
SetEvent(m_hEventStopMyWorkerThread);
WaitForSingleObject(m_hEventMyWorkerThreadKilled, 3000); //waiting
for the worker thread to be killed.
}
CloseHandle(m_hEventStopMyWorkerThread);
CloseHandle(m_hEventMyWorkerThreadKilled);
}
void CMyDlg::OnDestroy()
{
CDialog::OnDestroy();
// wind down any worker thread in progress if user says cancel
SetEvent(m_hEventStopMyWorkerThread);
m_isDialogClosing = TRUE;
WaitForSingleObject(m_hEventMyWorkerThreadKilled, 3000);
}
void CMyDlg::OnWorkButton()
{
// Start Worker thread.
ResetEvent(m_hEventStopMyWorkerThread);
m_pMyWorkerThread = AfxBeginThread(CMyDlg::WorkerFunction, this);
}
UINT CMyDlg::WorkerFunction(LPVOID pParam)
{
CMyDlg* p_Dlg = static_cast<CMyDlg*>(pParam);
if (p_Dlg->m_isDialogClosing)
{
SetEvent(p_Dlg->m_hEventMyWorkerThreadKilled);
return 0;
}
p_Dlg->DoSomeHeavyJob();
WaitForSingleObject(p_Dlg->m_hEventStopMyWorkerThread, 30000);
if (! p_Dlg->m_isDialogClosing)
p_Dlg->DoSomeHeavyJob();
else
SetEvent(p_Dlg->m_hEventMyWorkerThreadKilled);
p_Dlg->m_pMyWorkerThread = NULL;
return(0);
}