线程的安全关闭和释放

主要有三种方式:1 返回0 2 通过线程id发送中断消息给该线程 3:waitforobject信号退出

参考1 通过线程id发送消息

线程返回0进行安全退出

VC++工作者线程关闭的问题 主线程和子线程

VC++线程的创建和关闭

重点: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);

  }

  }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值