线程没有正常结束产生的内存泄露问题的解决

   在毕设程序的收尾阶段,首先发现内存泄露的地方,是在线程的不能正常结束导致线程所占有的资源无法被释放。如下:

Detected memory leaks!
Dumping objects ->
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306): {396} client block at 0x003BBE18, subtype c0, 68 bytes long.
a CWinThread object at $003BBE18, 68 bytes long
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306): {390} client block at 0x01313580, subtype c0, 68 bytes long.
a CWinThread object at $01313580, 68 bytes long
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306): {208} client block at 0x003BFF80, subtype c0, 68 bytes long.
a CWinThread object at $003BFF80, 68 bytes long
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306): {205} client block at 0x003BFF00, subtype c0, 68 bytes long.
a CWinThread object at $003BFF00, 68 bytes long
Object dump complete.
程序“[4048] TetrisGame.exe: 本机已退出,返回值为 0 (0x0)

 

      这类的内存泄露乍一看,那个文件../ thrdcore.cpp(306) 不是自己写的啊,怎么会在那里产生MemoryLeak 呢?难道MFC有Bug? 想不明白。

  经过一番研究思考,发现原来是自己程序结束时,所开的线程还没有被Kill ,于是动手修改之。

  问题解决,现在记录过程如下,以备以后参考。

  一、总共建立四个全局线程函数:

//头文件里declare四个线程指针

//----- Thread Control :
private:
 CWinThread*m_pThread_ListenBcast;    
 CWinThread*m_pThread_ListenConnect;   
 CWinThread *m_pThread_ListenGSP;
 CWinThread *m_pThread_ListenGAM;
// ----  Thread Control :~

 

//CView.cpp文件里declare Thread End Control Flags 和 线程函数

//--- Thread Control:
BOOL g_bThread_ListenBcast_MustEnd;               // Global variable flag to control Thread End
BOOL g_bThread_ListenConnect_MustEnd;     // Global variableflag to control Thread End
BOOL g_bThread_ListenGAM_MustEnd;      // Global variableflag to control Thread End
BOOL g_bThread_ListenGSP_MustEnd;      // Global variableflag to control Thread End

UINT Thread_Listen_Broadcast( LPVOID pParam );
UINT Thread_Listen_Connect( LPVOID pParam );
UINT Thread_Listen_RivalGSPack( LPVOID pParam );
UINT Thread_Listen_RivalGAMPack( LPVOID pParam );
// --- Thread Control:~

  

   二、程序开始时,在view的构造函数里要首先对线程进行初始化和beginthread 的工作:

// ----- Thread Control :
 g_bThread_ListenBcast_MustEnd = FALSE;
 m_pThread_ListenBcast = AfxBeginThread(Thread_Listen_Broadcast, m_hWnd );
 m_pThread_ListenBcast->m_bAutoDelete =FALSE;  // The thread manually deleted
 g_bThread_ListenConnect_MustEnd = FALSE;
 m_pThread_ListenConnect = AfxBeginThread(Thread_Listen_Connect, m_hWnd );
 m_pThread_ListenConnect->m_bAutoDelete =FALSE;

 g_bThread_ListenGAM_MustEnd = FALSE;
 m_pThread_ListenGAM = NULL;

 g_bThread_ListenGSP_MustEnd = FALSE;  
 m_pThread_ListenGSP = NULL;
 // ----  Thread Control :~

   如果不对m_pThread_ListenGAM 和 m_pThread_ListenGSP 初始化为NULL ,在Debug 时会被引发断点,如:

   TetrisGame.exe 中的 0x0042e014 处最可能的异常: 0xC0000005: 读取位置 0xcdcdcdf9 时发生访问冲突
   TetrisGame.exe 中的 0x0042e014 处未处理的异常: 0xC0000005: 读取位置 0xcdcdcdf9 时发生访问冲突

  以后再遇到"异常:0xC0000005: 读取位置0xcdcdcdf9 时发生访问冲突",就知 某个指针变量没有进行初始化,所以构造函数时应该对所有的指针变量进行赋初值为NULL。

 

   三、然后是在OnBeginOnLineFight 函数里 begin 两外两个线程:

LRESULTCTetrisGameView::OnBeginOnLineFight( WPARAM, LPARAM )
{
      //----------------------------------Till_Here_2011-04-16 --------------------------------//
      // 1 Send a message to MainFrame, to redraw theDouble GA
      CFrameWnd *pActiveFrame = (CFrameWnd *)(AfxGetApp()->m_pMainWnd );
      if ( NULL != pActiveFrame )
      {
          pActiveFrame->SendMessage( MSG_To_MainFram_Redraw_Double_GA, 0, 0 );
      }

     // 2 POL Begin
      g_pP2P->Set_bStartPOL( true );

     g_bThread_ListenGAM_MustEnd = FALSE;
     g_bThread_ListenGSP_MustEnd = FALSE;

     // 2.1 Begin Thread_Listen_RivalGAMPack and  Thread_Listen_RivalGSPack
      m_pThread_ListenGAM= AfxBeginThread( Thread_Listen_RivalGAMPack, NULL );
      m_pThread_ListenGAM->m_bAutoDelete= FALSE;  // The thread manually deleted
      m_pThread_ListenGSP= AfxBeginThread( Thread_Listen_RivalGSPack, NULL );
      m_pThread_ListenGSP->m_bAutoDelete= FALSE;  // The thread manually deleted

      //2.2 First begin PM( Play myself )
      m_pTe->GameStart( m_hWnd );

      //2.3 Second redraw the Rival's GA, Rival starts
      g_pTePOL->Rival_GameStart( m_hWnd);    

     return 0;
}

 

  四、最后在析构函数里,进行对线程进行关闭和Clear工作:

//1  ----- Thread Terminate :
 // Set flags
 g_bThread_ListenBcast_MustEnd = TRUE;
 g_bThread_ListenConnect_MustEnd = TRUE;

 g_bThread_ListenGAM_MustEnd = TRUE;
 g_bThread_ListenGSP_MustEnd = TRUE;

 //Clear
 if ( m_pThread_ListenBcast )
 {
       if (WaitForSingleObject( m_pThread_ListenBcast->m_hThread, 100 ) == WAIT_TIMEOUT)
      {      
             TerminateThread(m_pThread_ListenBcast->m_hThread, NULL ); 
            TRACE("\n\t:-0 _1 Thread_Listen_Broadcast be terminated atlast.\n"); 
       }   
       CloseHandle(m_pThread_ListenBcast->m_hThread );
       m_pThread_ListenBcast->m_hThread= NULL;
      Safely_Delete_Pointer( m_pThread_ListenBcast );
 }   
 if ( m_pThread_ListenConnect )
 {    
       if (WaitForSingleObject( m_pThread_ListenConnect->m_hThread, 100 ) ==WAIT_TIMEOUT )
       {      
             TerminateThread( m_pThread_ListenConnect->m_hThread, NULL );

             TRACE("\n\t:-0 _2 Thread_Listen_Connect be terminated atlast.\n");  
       }   

       CloseHandle(m_pThread_ListenConnect->m_hThread );
      m_pThread_ListenConnect->m_hThread = NULL;
      Safely_Delete_Pointer( m_pThread_ListenConnect );
 } 
 if ( m_pThread_ListenGAM )
 {
      TerminateThread( m_pThread_ListenGAM->m_hThread, NULL );
      TRACE("\n\t:-0 _3 Thread_Listen_GAM be terminated at last.\n"); 
       CloseHandle(m_pThread_ListenGAM->m_hThread );
      m_pThread_ListenGAM->m_hThread = NULL;
      Safely_Delete_Pointer( m_pThread_ListenGAM );
 } 
 if ( m_pThread_ListenGSP )
 {
       TerminateThread(m_pThread_ListenGSP->m_hThread, NULL );
       TRACE("\n\t:-0_4 Thread_Listen_GSP be terminated at last.\n"); 

       CloseHandle(m_pThread_ListenGSP->m_hThread );
      m_pThread_ListenGSP->m_hThread = NULL;
      Safely_Delete_Pointer( m_pThread_ListenGSP );
 } 
 // ----  Thread Terminate :~

 

 

   五、附上四个线程函数:

//
// ==== Davy's manual Thread Functions:

UINT Thread_Listen_Broadcast( LPVOID pParam )
{
 while ( ! g_bThread_ListenBcast_MustEnd )
 { 
  // 1 Cover
  if ( !g_pP2P )
  {
   TRACE("\n\t-->| :-) _1 Thread_Listen_Broadcast returnNormally. \n");
   return 0;
  } 

  //2
  if ( g_pP2P )
  {
   g_pP2P->Listen_Broadcast();
  }
     
  Sleep( 80 );    
 } 

 TRACE("\n\t:-)_1 Thread_Listen_Broadcast return Normally.\n"); 
 return 0;   
}

UINTThread_Listen_Connect( LPVOID pParam )
{
 while ( ! g_bThread_ListenConnect_MustEnd )
 {
  // 1 Cover
  if ( !g_pP2P )
  {
   TRACE("\n\t-->| :-) _2 Thread_Listen_Connect returnNormally. \n");
   return 0;
  } 

  //2 Listen Connect Or AcceptFight_RefuseFight
  if ( g_pP2P )
  {
   g_pP2P->Listen_Connect_Or_AcceptFight_RefuseFight();
  }   

  //3 Get the Connect Type
  if ( g_pP2P && g_pP2P->Get_bSucceedConnect() )
  {
   // Get this's View Pointer:
   CView *pView = ( (CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   // :~
   if ( pView )
   {
    pView->PostMessage( MSG_CONNECT_REQUEST, 0, 0 );
   }   
  }
  else if ( g_pP2P && g_pP2P->Get_bAcceptFightRequest() )
  {
   CView *pView = ( (CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   if ( pView )
   {
    pView->PostMessage( MSG_Rival_Accept_Fight_Request,0, 0 );
   }
  }
  else if ( g_pP2P && g_pP2P->Get_bRefuseFightRequest() )
  {
   CView *pView = ( (CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   if ( pView )
   {
    pView->PostMessage( MSG_Rival_Refuse_Fight_Request,0, 0 );
   }
  }
  // ---------------------------- Loser and Winner :
  else if ( g_pP2P && g_pP2P->Get_bRecvLoserWouldNotFA() )
  {
   //
   CView *pView = ( ( CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   if ( pView )
   {
    pView->PostMessage( MSG_LoserWouldNotFA, 0, 0 );
   }
  } 
  else if ( g_pP2P && g_pP2P->Get_bRecvLoserFAR() )
  {
   //
   CView *pView = ( ( CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   if ( pView )
   {
    pView->PostMessage( MSG_LoserWantFightAgain, 0, 0 );
   }
  } 
  else if ( g_pP2P && g_pP2P->Get_bAcceptLoserFAR() )
  {
   CView *pView = ( ( CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   if ( pView )
   {
    pView->PostMessage( MSG_WinnerAcceptLoserFAR, 0, 0);
   }
  } 
  else if ( g_pP2P && g_pP2P->Get_bRefuseLoserFAR() )
  {
   CView *pView = ( ( CFrameWnd *)( AfxGetApp()->m_pMainWnd ))->GetActiveView();
   if ( pView )
   {
    pView->PostMessage( MSG_WinnerRefuseLoserFAR, 0, 0);
   }
  } 

  //3 Pause for 80 ms
  Sleep( 80 ); 
 }

 TRACE("\n\t:-)_2 Thread_Listen_Connect return Normally.\n");
 return 0;    
}
UINT Thread_Listen_RivalGSPack( LPVOID pParam )
{
 while ( ! g_bThread_ListenGSP_MustEnd )
 {
  // 1 Cover
  if ( !g_pP2P || ! g_pP2P->Get_bStartPOL() )
  {
   TRACE("\n\t-->| Thread_Listen_RivalGSPack returnnormally at last. :-) \n");
   return 0;
  }

  //2 Listen RivalGSPack
  if ( g_pP2P && !g_pP2P->Listen_RivalGSPack( (AfxGetApp()->m_pMainWnd )->m_hWnd ) )  
  {
   TRACE("\n\t-->| Thread_Listen_RivalGSPack()_Fail toListen_RivalGSPack. :-( \n");
  }

  //2 Pause for 40 ms
  Sleep( 40 ); 
 }

 //3 Return
 TRACE("\n\t :-) _3 Thread_Listen_RivalGSPack return normally atlast. \n");
 return 0; 
}

UINTThread_Listen_RivalGAMPack( LPVOID pParam )
{
 while ( ! g_bThread_ListenGAM_MustEnd )
 {
  // 1 Cover
  if ( !g_pP2P || !g_pP2P->Get_bStartPOL() )
  {
   TRACE("\n\t-->| Thread_Listen_RivalGAMPack returnnormally at last. :-) \n");
   return 0;
  } 

  //2 Listen RivalGAMPack
  if ( g_pP2P && !g_pP2P->Listen_RivalGAMPack() )
  {
   TRACE("\n\t-->| Thread_Listen_RivalGAMPack()_Fail toListen_RivalGAMPack. :-( \n");
  }

  //2 Pause for 10 ms
  Sleep( 10 ); 
 }

 //3 Return
 TRACE("\n\t:-) _4 Thread_Listen_RivalGAMPack return normally atlast.  \n");
 return 0; 
} //:~

//


还有程序里用到的一个宏定义:

#define Safely_Delete_Pointer( pX )   \
{                                                                \
     if ( NULL != pX)                                \
    {                                                            \
         deletepX;                                       \
         pX =NULL;                                    \
    }                                                            \
}


转自:http://wenku.baidu.com/view/96505a40a8956bec0975e3a9.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值