呵呵,说揭秘其实是说给自己听的,因为今天做了个MFC多线程优先级的例子,在线程里面使用了AfxGetMainWnd()->MDIGetActive(),返回值类型暂不讨论,就是这套东西在线程中具有诡异现象,查了一点说是线程里面有个map记录了窗口指针和其句柄的映射关系,使得有些指针不好使。等查明后在补全这里。
  
 今天主要写的是另一个问题,创建工作线程时,AfxBeginThread返回的CWinThread的对象指针所指的对象在默认情况下会自动删除。如果你不想让他自己删除,而且自己想查看线程信息的话,只需要在创建之后,用返回的CWinThread对象指针来设置m_bAutoDelete成员变量为FALSE即可。
  
 而我很好奇的是,为什么返回的CWinThread可以自动删除呢?
 其实光看别人说的自己知道遍罢,其实《深入浅出MFC》中侯老爷子谆谆教导:“在线程结束时,记得把该对象释放掉(利用delete)。”,就是因为这句话,让我的程序中断好几次,错误居然是销毁已经清理了的内存空间。后来查最新资料才知道,默认是会自动删除的。可能侯老爷子当时版本太低,或者其他原因吧。但是侯老爷子说过:“学一样东西,只知道怎么用,但不明白其中的道理,实在是不高明”。再加上本身我就是遇到问题非得心里有底才行,光听别人说是这样,不明白为什么,总觉得心里用的不踏实。好了,废话就不说了,切入正题。
  
 为什么AfxBeginThread函数动态创建的对象会在线程结束后自动销毁呢?难道是有什么消息映射?任何东西究其根源离不开他本身,先去看看AfxbeginThread的源码:
 
  
 没有发现什么端倪,一切很合情合理。但是书上说过AfxEndThread()就像,_beginthread和_endthread一样配对。那让我们去看一下AfxEndThread()。下面是源码:
 
-  void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete)  
-  {  
-  #ifndef _MT  
-      nExitCode;  
-      bDelete;  
-  #else  
-        
-      AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();  
-      CWinThread* pThread = pState->m_pCurrentWinThread;  
-      if (pThread != NULL)  
-      {  
-          ASSERT_VALID(pThread);  
-          ASSERT(pThread != AfxGetApp());  
-    
-            
-          if (pThread->m_lpfnOleTermOrFreeLib != NULL)  
-              (*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);  
-    
-          if (bDelete)  
-              pThread->Delete();  
-          pState->m_pCurrentWinThread = NULL;  
-      }  
-    
-        
-      AfxTermThread();  
-    
-        
-      _endthreadex(nExitCode);  
-  #endif //!_MT  
-  }  
 
 其中我们看到bDelete,原来删除工作都在这呢,看:
 if(bDelete)
     pThread->Delete();
  
 那么我们去看看CWinThread::Delete():
 
-  void CWinThread::Delete()  
-  {  
-        
-      if (m_bAutoDelete)  
-          delete this;  
-  }  
 
  
 原来,如果m_bAutoDelete是真时,这个函数内部会将自己删除。
 这么看来,我们可以大胆猜测,肯定是线程函数结束后自动调用了这个函数。而我们看的这几个代码,全然没有。但是我们还有一个重要的函数没有看:那么就AfxBeginThread里面的CWinThread::CreateThread。让我们去看看:
  
 
-  BOOL CWinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize,  
-      LPSECURITY_ATTRIBUTES lpSecurityAttrs)  
-  {  
-  #ifndef _MT  
-      dwCreateFlags;  
-      nStackSize;  
-      lpSecurityAttrs;  
-    
-      return FALSE;  
-  #else  
-      ENSURE(m_hThread == NULL);    
-    
-        
-      _AFX_THREAD_STARTUP startup; memset(&startup, 0, sizeof(startup));  
-      startup.pThreadState = AfxGetThreadState();  
-      startup.pThread = this;  
-      startup.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);  
-      startup.hEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);  
-      startup.dwCreateFlags = dwCreateFlags;  
-      if (startup.hEvent == NULL || startup.hEvent2 == NULL)  
-      {  
-          TRACE(traceAppMsg, 0, "Warning: CreateEvent failed in CWinThread::CreateThread./n");  
-          if (startup.hEvent != NULL)  
-              ::CloseHandle(startup.hEvent);  
-          if (startup.hEvent2 != NULL)  
-              ::CloseHandle(startup.hEvent2);  
-          return FALSE;  
-      }  
-    
-        
-      m_hThread = (HANDLE)(ULONG_PTR)_beginthreadex(lpSecurityAttrs, nStackSize,    
-          &_AfxThreadEntry, &startup, dwCreateFlags | CREATE_SUSPENDED, (UINT*)&m_nThreadID);  
-      if (m_hThread == NULL)  
-      {  
-          ::CloseHandle(startup.hEvent);  
-          ::CloseHandle(startup.hEvent2);  
-          return FALSE;  
-      }  
-    
-          ...  
-  #endif //!_MT  
-  }  
 
  
  
 让我们看看这个_AfxThreadEntry鬼东西:
 
-  UINT APIENTRY _AfxThreadEntry(void* pParam)  
-  {  
-      _AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;  
-      ASSERT(pStartup != NULL);  
-      ASSERT(pStartup->pThreadState != NULL);  
-      ASSERT(pStartup->pThread != NULL);  
-      ASSERT(pStartup->hEvent != NULL);  
-      ASSERT(!pStartup->bError);  
-    
-      CWinThread* pThread = pStartup->pThread;  
-      CWnd threadWnd;  
-      TRY  
-      {  
-            
-          _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();  
-          pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;  
-    
-            
-          AFX_MODULE_STATE* pModuleState = AfxGetModuleState();  
-          pThread->m_pModuleState = pModuleState;  
-          AFX_MODULE_THREAD_STATE* pState = pModuleState->m_thread;  
-          pState->m_pCurrentWinThread = pThread;  
-    
-            
-          AfxInitThread();  
-    
-            
-          CWinApp* pApp = AfxGetApp();  
-          if (pApp != NULL &&   
-              pThread->m_pMainWnd == NULL && pApp->m_pMainWnd->GetSafeHwnd() != NULL)  
-          {  
-                
-              threadWnd.Attach(pApp->m_pMainWnd->m_hWnd);  
-              pThread->m_pMainWnd = &threadWnd;  
-          }  
-      }  
-      CATCH_ALL(e)  
-      {  
-            
-    
-            
-          TRACE(traceAppMsg, 0, "Warning: Error during thread initialization!/n");  
-    
-            
-          threadWnd.Detach();  
-          pStartup->bError = TRUE;  
-          VERIFY(::SetEvent(pStartup->hEvent));  
-          AfxEndThread((UINT)-1, FALSE);  
-          ASSERT(FALSE);    
-      }  
-      END_CATCH_ALL  
-    
-          ......  
-        
-      DWORD nResult = 0;  
-      if (pThread->m_pfnThreadProc != NULL)  
-      {  
-          nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);  
-          ASSERT_VALID(pThread);  
-      }  
-        
-      else if (!pThread->InitInstance())  
-      {  
-          ASSERT_VALID(pThread);  
-          nResult = pThread->ExitInstance();  
-      }  
-      else  
-      {  
-            
-          ASSERT_VALID(pThread);  
-          nResult = pThread->Run();  
-      }  
-    
-        
-      threadWnd.Detach();  
-      AfxEndThread(nResult);  
-    
-      return 0;     
-  }  
 
  
 你看58行:
 nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
 还有最后那行:
 AfxEndThread(nResult);
  
 原来啊,我们自己的线程函数在mfc的线程函数成了函数调用了。呵呵。最后这个AfxEndThread(nResult),就是我们一直找的。
 其实我们可以在自己的线程里直接用AfxEngThread来清理CWinThread对象,这样mfc的线程自己在调用的AfxEndThread的时候,里面有自检机制,就不会再销毁一次了。
  
 源码说明一切。侯老爷子说的。