摘自http://www.cnblogs.com/busuncle/archive/2010/05/17/1737467.html
MFC下结束AfxBeginThread开启的线程的一些体会
最近,由于论文的需求,要用到Windows下的多线程。考虑到界面用MFC写 了,于是上网搜了下MFC下的多线程怎样搞,都说用AfxBeginThread来日比较好。哥向来比较浮躁,先搜搜有没相关代码,找到几个可用的,然后 各种摘抄,于是乎将哥的播放器的几个线程搞成下面这段代码(摘要):
UINT playThread(LPVOID pParam){ //播放线程,固定格式
//......做变量声明,赋值等前期工作
while(SomeCondition){ //播放线程的循环
//......播放音乐,不解析
}
return 0;
}
void CPlayerDlg::OnBnClickedPlay(){ //播放按钮响应函数
if(isThreadPause){ //判断是否暂停中
isThreadPause=false;
pPlayerThread->ResumeThread();//继续播放
}
else{
OnBnClickedStop();
pPlayerThread=AfxBeginThread(playWaveThread,NULL); //开启播放线程
}
}
void CPlayerDlg::OnBnClickedPause(){ //暂停响应函数
if(!isThreadPause){
PlayerThread->SuspendThread(); //挂起进程,相当于暂停播放
isThreadPause=true;
}
}
void CPlayerDlg::OnBnClickedStop(){ //终止响应函数
if(pPlayThread){
isThreadPause=false;
TerminateThread(pPlayerThread->m_hThread,0);//强行终止线程,这里有问题,后面说
}
}
其中播放线程playThread的声明是固定那种格式的,而且最好写成全局函数,方便,如果写成类成员函数的话又要加static,调用时又要加作用域的,十分蛋痛。写完后果断运行,yeah,能播放、暂停和停止,相当舒服,也没去理会细节的问题。
直到今天,心血来潮地打开任务管理器,看看程序内存占用情况,发现了一个狠严重的问题:每当我停止一首歌,播放下一首时,内存就突然间往上跳。 一开始以为是正常的内存创建和回收造成的浮动,但我继续不断地重复播放停止、播放停止,发现内存一直往上升。虽然每次都只是上升一点点,但明摆着的 memory leak搁在那,还不搞它哥以后怎样出来混?
好,果断google之,发现问题出在TerminateThread这个函数。这个TerminateThread结束线程用的是相当暴力的 方法,据说连里面的局部变量都不释放。这就草了,马上寻找解决办法,有人回帖说用CreateEvent和WaitForSingleObject结合日 之,解释没解释清楚,给出的sample code也是相当纠结和羞涩,而且楼下跟帖说这种方法有可能阻塞死锁之类的。果断放弃,看 到另外一种方法,就是在停止的响应函数里用::PostThreadMessage(由于播放线程是全局函数,所以前面要加::)给播放线程发送停止消 息,播放线程里加一个MSG的变量和while,每次里面调用PeekMessage来检查是否发来停止的消息,写了下,代码相当简练明了:
#define WM_THREAD_STOP 0x0427 //自定义一个消息,也可以用系统定义的如WM_QUIT
UINT playWaveThread(LPVOID pParam){
//......做变量声明,赋值等前期工作
while(SomeCondition){ //播放线程的循环
MSG msg; //增加一个MSG的变量msg来接收消息
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ //将消息队列里的消息逐个读入msg
if(msg.message==WM_THREAD_STOP){ //如果收到终止消息则退出
//TODO:放在堆里的变量要在这里手动清理
return 0; //线程正常返回,会释放局部变量等内存资源
}
else{
DispatchMessage(&msg);//字面意思,不解释
}
}
//......播放音乐,不解析
}
return 0;//正常播放结束,释放资源
}
void CPlayerDlg::OnBnClickedPlay(){……}//播放按钮响应函数,不变
void CPlayerDlg::OnBnClickedPause(){……}//暂停响应函数,也不变
void CPlayerDlg::OnBnClickedStop(){
if(pPlayerThread){
isThreadPause=false;
//原来的TerminateThread不用,换成下面这个
::PostThreadMessage(pPlayerThread->m_nThreadID,WM_THREAD_STOP,0,0);
}
}
写完,果断运行并打开任务管理器监测,诶!果然没有出现之前的内存一直在涨的现象,十分舒服,搞定收工!话说本人刚学多线程,代码写得相当的水,如果哪位大牛看到这处理方法还存在什么问题望不吝赐教,谢谢!
相关推荐
采用AfxBeginThread创建工作线程。采用素数的判断来演示,涉及到多参数的传递,消息的响应和信息的实时显示等。
如标题,在MFC中必须使用 AfxBeginThread创建多线程,如使用BeginThread可能会出现BUG
新建一个Therad名称的对话框文件,对资源视图上拖一个编辑框控件.程序运行后用线程函数调用系统时间方式在编辑框上显示.
分别采用AfxBeginThread CreateThread 创建线程其中AfxBeginThread工程用的是vs2010 CreateThread 工程用的是vc6.0
在MFC程序中创建一个线程,宜调用AfxBeginThread函数。该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程。 工作者线程 CWinThread *AfxBeginThread( AFX_THREADPROC ...
此资源在VC++6.0上开发,一个简单的线程测试程序,MFC线程,线程创建使用AfxBeginThread函数,生成可执行程序(.exe)
现在,考察该函数:MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,分别有如下的原型和过程: 用户界面线程的AfxBeginThread 用户界面线程的AfxBeginThread的原型如下: ...
在MFC程序中创建一个线程,宜调用AfxBeginThread函数。该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程。 工作者线程 CWinThread *AfxBeginThread( AFX_THREADPROC ...