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