请问我这段多线程代码为什么会死机?
我在写个多线程的代码,建立一个对话框,放置“开始”“通知”“进度条”控件。我的目的是按“开始”执行“ThreadFunc”函数,按“停止”中止执行。代码如下:
- C/C++ code
void CSolverDlg::ForceQuit(){ SetEvent(hExit);};BOOL CSolverDlg::IsForceQuit(){ return WaitForSingleObject(hExit,0) == WAIT_OBJECT_0 ;};void CSolverDlg::OnBnClickedStart(){ // TODO: 在此添加控件通知处理程序代码 if (m_MyThread != NULL) { DWORD dwExitCode = -1; VERIFY( GetExitCodeThread(*m_MyThread, &dwExitCode) ); if (dwExitCode == STILL_ACTIVE) { TRACE("是否在运行1\n"); return; } delete m_MyThread; m_MyThread = NULL; } m_MyThread =AfxBeginThread( ThreadFunc, (LPVOID)this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); ASSERT(m_MyThread); m_MyThread->m_bAutoDelete = FALSE; m_MyThread->ResumeThread();}void CSolverDlg::OnBnClickedStop(){ // TODO: 在此添加控件通知处理程序代码 if (m_MyThread != NULL) { DWORD dwExitCode = -1; VERIFY( GetExitCodeThread(*m_MyThread, &dwExitCode) ); if (dwExitCode == STILL_ACTIVE) { ForceQuit(); WaitForSingleObject(*m_MyThread,INFINITE); delete m_MyThread; m_MyThread = NULL; } } else TRACE("已结束\n");}UINT ThreadFunc(LPVOID pParam){ CSolverDlg * pMain = (CSolverDlg *) pParam; //强制转换获得传入的类对象指针 pMain->m_Progress.SetRange(0, 30 ); for (int i=0; i<30; i++) { TRACE("在运行11\n") ; if (pMain->IsForceQuit()) { TRACE("停止1\n") ; return -1; } TRACE("在运行13\n") ; Sleep(5000);//休眠5秒钟 TRACE("在运行14\n") ; pMain->m_Progress.SetPos(i); TRACE("在运行12\n") ; } return 0;};当按停止键时,执行到“pMain->m_Progress.SetPos(i);”这步就死机了,这是为什么?
[解决办法]
“pMain->m_Progress.SetPos(i);”会通过SendMessage函数给主线程发送消息,但是此时主线程处于“WaitForSingleObject(*m_MyThread,INFINITE);”的等待中,无法处理消息,造成死锁。
特别提示:线程函数尽量不要操作UI界面。
解决方案有两个:
一个是“pMain->m_Progress.SetPos(i);”通过给主线程PostMessage方式,让主线程更新。
另一个是“WaitForSingleObject(*m_MyThread,INFINITE);”替换成while循环,使用PeekMessage和带超时的WaitForSingleObject函数调用组合检测线程是否退出。
[解决办法]
跨线程SendMessage,比如在线程A中给主线程发消息,线程A会挂起,直到主线程里这个消息处理完。MFC里很多成员函数内部都是通过SendMessage来实现的。