MFC创建用户线程,直接关闭程序时,线程就报错了.怎么让它安全退出

MFC创建用户线程,直接关闭程序时,线程就报错了.如何让它安全退出?
本帖最后由 iceelee 于 2015-10-01 15:05:32 编辑
我创建了一个MFC的对话框程序,有个按扭事件创建了一个线程。线程的功能是进行一个很耗时的计算,
这个线程要能支持暂停和停止功能。而且线程中的计算过程,数据需要实时的展示到界面上。

代码很简单的,
就是一个按扭控制线程的创建和结束,
另一个按扭控制线程的暂停和继续,
线程计算出来的数据发消息通知另一函数更新到界面上展示。

线程创建和执行计算,以及实时展示总体是这样子的:


LRESULT  CMainDlg::WoekerThread(LPARAM lParam)
{  //线程函数
    CMainDlg* pDlg = (CMainDlg*)lParam;
    pDlg->CalcData();  //调用计算模块,这样写的目的是为了简单,免得在线程里调用类成员变量和函数还得加pDlg->xxx
    return 0;
}

void CMainDlg::CalcData()
{
     while (m_bStartCalc)
    {
        m_dwCurrentVal = GetValue();  //进行计算
        m_SomeOtherData = xxxxxxx;    //一些其他计算,更新另外一部分成员变量的值
        SendMessage(UM_UPDATEPROCESS);   //发消息通知主线程要更新展示数据,由消息函数UpdateProcess处理这个消息
        //没有用PostMessage的目的是因为我计算时需要使用类成员变量,数据展示也需要使用类成员变量,以免冲突
        WaitForSingleObject(m_hPuaseEvent, INFINITE); //这个事件用来控制线程暂停
    }
    m_bStartCalc = FALSE;  
}

LRESULT CMainDlg::UpdateProcess(WPARAM wParam, LPARAM lParam)
{ //更新展示信息的消息函数
    CString strCurVal;
    strCurVal.Format(_T("当前计算值:%u"), m_dwCurrentVal);
    SetDlgItemText(IDD_STATIC_PROCESS, strCurVal);
    UpdateData(FALSE);     //有一些控件绑定了控件变量,在线程中改变那些变量值后,直接用UpdateData来更新
}

void CMainDlg::OnStartBtn()
{//线程启动和停止按扭事件
    if (m_bStartCalc)
    {//说明线程已经在运行中,将m_bStartCalc置成FALSE,让线程的循环退出

        m_bStartCalc = FALSE;
        if (m_hPuaseEvent && m_bPause)//线程是暂停状态的话,要将事件置成有信号状态,让线程运行起来 
        {//避免线程一直是等待事件暂停状态,就不能退出了
            SendEvent(m_hPuaseEvent);
        }
        
        SetDlgItemText(IDB_BTN_START, _T("开始"));  
    }
    else
    {
        if (m_hPuaseEvent == NULL)
        {//通过事件来控制线程暂停
            m_hPuaseEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
        }
        
        m_bStartCalc = TRUE;
        m_pWinThread = AfxBeginThread((AFX_THREADPROC)WoekerThread, this, THREAD_PRIORITY_HIGHEST, CREATE_SUSPENDED);
        m_pWinThread->m_bAutoDelete = FALSE;
        m_pWinThread->ResumeThread();
        SetDlgItemText(IDB_BTN_START, _T("停止"));
    }
}

void CMainDlg::OnPauseBtn()
{//线程暂停和继续按扭事件
    if (m_pWinThread)
    {
        if (m_bPause)
        {
            SendEvent(m_hPuaseEvent); //如果是暂停状态,将事件置成有信号,让线程内的循环继续运行机制
            m_bPause = FALSE;
            SetDlgItemText(IDB_BTN_PAUSE, _T("暂停"));
        }
        else
        {
            m_bPause = TRUE;
            ResetEvent(m_hPuaseEvent);
            SetDlgItemText(IDB_BTN_PAUSE, _T("继续"));
        }   
    }
}


void CMainDlg::OnClose()
{
    if (m_bStartCalc)
    {//这个方法也会抱错,为什么呢?    
        m_bStartCalc = FALSE;
        Sleep(1000);     
    }
    

    if (m_pWinThread && m_bStartCalc )
    {//这个也会抱错
        m_bStartCalc = FALSE;
        WaitForSingleObject(m_pWinThread->m_hThread, 1000);
    }
    CDialog::OnClose();
}



现在遇到一个问题,就是如果线程还在循环运行着,用户直接关闭程序,程序退出时会报错。要如何避免这样的错误发生呢?
或者说想进行这种类型的计算和控制,线程应该如何设计?

补充:我在OnClose()中将m_bStartCalc置成FALSE,然后 Sleep一下,还是会报错。 或者调用Wait
祝大家十一快乐。
------解决思路----------------------
MDI工程的主框架关闭是,是不会调用view类的onClose事件的,
只会调用主框架的onclose事件,应该在主框架的onclose中来清理view类的资源。

dialog工程不报错是因为dialog工程关闭时,会调用自己的onclose事件,而你在onclose事件中已经处理过了资源。所以不会出错了。