关于线程退出的问题

oldn123 2009-09-21 02:33:55
线程退出后死锁

我先把相关代码帖出来,问题描述在后面

void CMulThreadDialog::OnOK()
{
    ......
    m_pCmdThread = AfxBeginThread(CmdTdFunction, (LPVOID)this);
}

UINT __cdecl CMulThreadDialog::CmdTdFunction( LPVOID pParam )
{
CMulThreadDialog * pDlg = (CMulThreadDialog *)pParam;
pDlg->DoCommand();
PostMessage(WM_COMMAND, UM_ENDDIALOG, 0);
WriteLog(1000,1000,_T("the hthread: 0x%x run end"), pDlg->m_pCmdThread->m_hThread);
return 0;
}

void CMulThreadDialog::OnEndDialog()
{
MSG msg;
while(PeekMessage(&msg, this->m_hWnd,UM_SETPROGPOS,UM_SETPROGPOS,PM_REMOVE ));
while(PeekMessage(&msg, this->m_hWnd,UM_ENABLEUI,UM_ENABLEUI,PM_REMOVE ));
WriteLog(1000, 1000, _T("In OnEndDialog ...\tm_pCmdThread: 0x%x, HTHREAD: 0x%x"), m_pCmdThread, m_pCmdThread->m_hThread);
if (m_pCmdThread && m_pCmdThread->m_hThread)
{
WaitForSingleObject(m_pCmdThread->m_hThread, INFINITE); //1,偶尔会死在此处
}
VisLogLine(1000, 1000, _T("OnEndDialog End"));
CDialog::OnOK();  //2,偶尔会死在此处                           
}

问题是为什么我的线程函数已经走到return 0;了,但是我在OnEndDialog函数里输出的log中可以看到m_pCmdThread->m_hThread这个值偶尔是个有效的线程句柄值. 当这个值是个无效值时也就是说线程return后被autodelete掉了,所以handle变为无效(0xcdcdcdcd)程序可以正常退出,但有时这个值仍有效, 这时return 0也走了,线程有时会死在1处,偶尔还会死在CDialog::OnOK();里,很迷惑..
...全文
274 25 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
wangk 2009-09-22
  • 打赏
  • 举报
回复
对的m_bAutoDelete为TRUE的时候,线程return后,CWinThread *指向的指针内存对象被删除(这就是标准的野指针啊),所以不能并用。

至于是不是要用AutoDelete的模式要看你的应用,微软之所以把它的默认值设为TRUE,就是为了方便资源的自动释放。
oldn123 2009-09-22
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 wangk 的回复:]
你非要用等待 CWinThread对象指针的方式的话,在AfxBeginThread返回指针之后就把m_bAutoDelete置为FALSE,然后就能用WaitForSingleObject,楼上的诸位已经说的很清楚了。
[/Quote]
哦,好,这么说m_bAutoDelete = TRUE的模式和 WaitForSingleObject(m_pCmdThread->handle,..)这个不能并用是吧?
wangk 2009-09-22
  • 打赏
  • 举报
回复
你非要用等待 CWinThread对象指针的方式的话,在AfxBeginThread返回指针之后就把m_bAutoDelete置为FALSE,然后就能用WaitForSingleObject,楼上的诸位已经说的很清楚了。
oldn123 2009-09-22
  • 打赏
  • 举报
回复
谢谢 byxdaz 帮忙改的代码,我试下.
另外问一下什么情况下我们用autodelete的模式,什么情况下不要用?还是尽量都不要用autodelete 的模式?
bragi523 2009-09-22
  • 打赏
  • 举报
回复
你可以用GetExitCodeThread()得到一下退出码
看看是否等于STILL_ACTIVE
也可以用这个办法等待线程结束
byxdaz 2009-09-22
  • 打赏
  • 举报
回复
void CMulThreadDialog::OnOK()
{
    ......
    m_pCmdThread = AfxBeginThread(CmdTdFunction, (LPVOID)this,THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
m_pCmdThread->m_bAutoDelete = FALSE; // 保证线程退出码在外能被检查到。
m_pCmdThread->ResumeThread();
Sleep(100);
}

UINT __cdecl CMulThreadDialog::CmdTdFunction( LPVOID pParam )
{
CMulThreadDialog * pDlg = (CMulThreadDialog *)pParam;
pDlg->DoCommand();
PostMessage(WM_COMMAND, UM_ENDDIALOG, 0);
WriteLog(1000,1000,_T("the hthread: 0x%x run end"), pDlg->m_pCmdThread->m_hThread);
return 0;
}

void CMulThreadDialog::OnEndDialog()
{
MSG msg;
while(PeekMessage(&msg, this->m_hWnd,UM_SETPROGPOS,UM_SETPROGPOS,PM_REMOVE ));
while(PeekMessage(&msg, this->m_hWnd,UM_ENABLEUI,UM_ENABLEUI,PM_REMOVE ));
WriteLog(1000, 1000, _T("In OnEndDialog ...\tm_pCmdThread: 0x%x, HTHREAD: 0x%x"), m_pCmdThread, m_pCmdThread->m_hThread);
DWORD dwExitCode = STILL_ACTIVE;
while(1)
{
// 检索线程的退出代码前要求线程对象还没有退出
::GetExitCodeThread(m_pCmdThread->m_hThread, &dwExitCode);
if( dwExitCode != STILL_ACTIVE)
break;
}
// 手动删除线程对象
delete m_pCmdThread;
m_pCmdThread = NULL;
VisLogLine(1000, 1000, _T("OnEndDialog End"));
CDialog::OnOK();                            
}
oldn123 2009-09-22
  • 打赏
  • 举报
回复
谁能说下AutoDelete的方式,mfc内部是怎么自动结束掉线程并释放handle的么?
iqyely 2009-09-22
  • 打赏
  • 举报
回复
来关注下。
cnzdgs 2009-09-22
  • 打赏
  • 举报
回复
如果要等待线程结束,就不要用AutoDelete的方式了。创建线程时指定CREATE_SUSPENDED标志,然后将m_bAutoDelete设置为FALSE,再ResumeThread。
oldn123 2009-09-21
  • 打赏
  • 举报
回复
我刚看了下AfxBeginThread/AfxEndThread 里封装的就是event的形式,所以我在return 0;前掉了个AfxEndThread, 不知道是不是就可以了.
oyljerry 2009-09-21
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 oldn_cc_bird 的回复:]
如果你要等待的话,其实等待线程句柄不是很好,可以自己定义一个Event等对象,然后一个线程中wait,当另一个线程退出时,SetEvent触发..
_____________
嗯,对,我去等待一个事件也可以,但是我没懂你为什么说"等待线程句柄不是很好"?等句柄的方式会有什么问题呢?
[/Quote]
等待线程句柄一般最多就是7楼那种搞法,后面一直等待线程结束,如果要同步一般就用event好了
oldn123 2009-09-21
  • 打赏
  • 举报
回复
呵,楼上这么写是什么意思,sleep 100没什么意义吧?
这个死锁和peekmessage是不关系的
极速闪电 2009-09-21
  • 打赏
  • 举报
回复
MSG msg;
Sleep(100);
试试.
oldn123 2009-09-21
  • 打赏
  • 举报
回复
如果你要等待的话,其实等待线程句柄不是很好,可以自己定义一个Event等对象,然后一个线程中wait,当另一个线程退出时,SetEvent触发..
_____________
嗯,对,我去等待一个事件也可以,但是我没懂你为什么说"等待线程句柄不是很好"?等句柄的方式会有什么问题呢?
rendao0563 2009-09-21
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 oyljerry 的回复:]
m_pCmdThread = AfxBeginThread(CmdTdFunction, (LPVOID)this);
WaitForSingleObject(m_pCmdThread->m_hThread, INFINITE);  //这样等待

[/Quote]

你这样写会把当前线程阻塞住的.
oyljerry 2009-09-21
  • 打赏
  • 举报
回复
如果你要等待的话,其实等待线程句柄不是很好,可以自己定义一个Event等对象,然后一个线程中wait,当另一个线程退出时,SetEvent触发..
oldn123 2009-09-21
  • 打赏
  • 举报
回复
m_pCmdThread->m_hThread 值有效,可能并不是正确的线程handle,这样就有可能1处一直等待
____________
这个值我在线程建立时输出到log中过,这个handle就是建立时的handle没错.




回复于:2009-09-21 15:07:48
m_pCmdThread = AfxBeginThread(CmdTdFunction, (LPVOID)this);
WaitForSingleObject(m_pCmdThread->m_hThread, INFINITE); //这样等待
________________

你的意思是放到一个函数里??
还是什么意思,没懂.
在后面等和我在OnEndDialog里等有什么区别?



pDlg->DoCommand();
代码呢.
____________
Docommand这个是个虚函数,代码是子类中完成的.里面的内容较多
我想的是不管Docommand()里是什么东西他已经运行完毕了,那么他对这个死锁可能会有什么影响么?


oyljerry 2009-09-21
  • 打赏
  • 举报
回复
m_pCmdThread = AfxBeginThread(CmdTdFunction, (LPVOID)this);
WaitForSingleObject(m_pCmdThread->m_hThread, INFINITE); //这样等待
rendao0563 2009-09-21
  • 打赏
  • 举报
回复
pDlg->DoCommand();
代码呢.
oyljerry 2009-09-21
  • 打赏
  • 举报
回复
m_pCmdThread->m_hThread 值有效,可能并不是正确的线程handle,这样就有可能1处一直等待
加载更多回复(4)

15,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧