AfxBeginThread,_beginthreadex与CreateThread的关系

首先推荐用_beginthreadex创建线程,原因请看下文

转载

AfxBeginThread在内部直接调用了CreateThread创建线程而不是c语言下推荐的beginthreadex函数,而这两个函数是有区别的,主要是c运行库的历史遗留问题造成的。
在多线程环境中存在问题的C/C++运行期库变量和函数包括errno、_doserrno、strtok、_wcstok、strerror、_strerror、tmpnam、tmpfile、asctime、_wasctime、gmtime、_ecvt和_fcvt等。
若要使多线程C和C + +程序能够正确地运行,必须创建一个数据结构,并将它与使用
C / C + +运行期库函数的每个线程关联起来。当你调用C / C + +运行期库时,这些函数必须知道查
看调用线程的数据块,这样就不会对别的线程产生不良影响。
那么系统是否知道在创建新线程时分配该数据块呢?回答是它不知道。系统根本不知道你
得到的应用程序是用C / C + +编写的,也不知道你调用函数的线程本身是不安全的。问题在于你
必须正确地进行所有的操作。若要创建一个新线程,绝对不要调用操作系统的CreateThread函
数,必须调用C/C++运行期库函数_beginthreadex。
下面是关于_beginthreadex的一些要点:
• 每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位
于Mtdll.h文件中的Visual C++源代码中)。
• 传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也
保存在该数据块中。
• _beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的
唯一方法。
###可以看出调用_beginthreadex时分配了额外的内存空间。

如果调用CreateThread,而不是调用C / C + +运行期库的_beginthreadex来创建新线程,将会发生什么情况。当一个线程调用要求tiddata结构的C / C + +运行期库函数时,将会发生下面的一些情况(大多数C / C + +运行期库函数都是线程安全函数,不需要该结构)。首
先, C / C + +运行期库函数试图(通过调用TlsGetValue)获取线程的数据块的地址。如果返回
NULL作为tiddata块的地址,调用线程就不拥有与该地址相关的tiddata块。这时,C / C + +运行期库函数就在现场为调用线程分配一个tiddata块,并对它进行初始化。然后该tiddata块(通过TlsSetValue)与线程相关联。
###_beginthreadex相对应的推出函数是_endthreadex,这个函数会释放tiddata的内容。
---------------------------
如果你采用CreateThread创建线程,而你没有使用上面所提到的那些特殊运行期库的话,也是不会出现问题的;如果一定要用那些运行库的话就最好调用_beginthreadex 这个api来创建线程,否则tiddata数据块就无法撤销,引起内存泄漏。
你可以参照_beginthreadex源代码来进行理解。

第二骗转载http://chenlan511.blog.163.com/blog/static/17053221320109213452748

AfxBeginThread引起的内存泄漏

AfxBeginThread引起的内存泄漏(ZZ)

下面的代码,当用AfxBeginThread开始一个线程时,实际上是有内存泄漏的

for  (ii  =   0 ; ii  <   1000 ; ii ++ ) 
{
  CWinThread  * pWinThread; 
  pWinThread  =  AfxBeginThread(ThreadLBProc, NULL);
  ::Sleep( 500 );
}

UINT ThreadLBProc(LPVOID pParam)
{
   return   0 ;

VC输出的典型提示为:
Detected memory leaks!
Dumping objects ->
thrdcore.cpp(166) : {782} client block at 0x00425300, subtype 0, 112 bytes long.
实际上,只要看到是thrdcore.cpp(166) 的内存泄漏,基本就是同一个原因,和上面的代码一样。
解决方法:
step 1)
在线程函数中,记得写AfxEndThread();(与AfxBeginThread对应,其他的开始线程的函数,有相应的函数)
step 2)
用::WaitForSingleObject()确保线程彻底退出

step 2是比较容易忽略的,用sleep函数只能侥幸的保证线程退出,但不能确保。


今天又试了一下,发现恰当的应该是: 
AfxBeginThread -> CreateThread ->_beginthreadex -> _AfxThreadEntry 
而在_AfxThreadEntry中,会保证AfxEndThread会调用,这个时候,如果 
pWinThread->m_bAutoDelete == TRUE, 整个pWinThread会delete掉,pWinThread->m_hThread也就自然不是个有意义的值。 
所以: 
//code 1: 
//remember pWinThread for later use 
m_pWinThread = AfxBeginThread(ThreadLBProc, NULL); 
//不要自动删掉m_WinThread,保证pWinThread->m_hThread可用 
m_WinThread->m_bAutoDelete = FALSE;

//code 2 
WaitForSingleObject(pWinThread->m_hThread, INFINITE) 
delete pWinThread;//在使用完pWinThread->m_hThread后,再手工delete

你應該使用WaitSingleObject(線程句柄)來等待線程退出,而不應用sleep.
另外,你的線程是使用循環測試stoploop=false來控制線程的退出嗎? 如果這樣的話,你應把stoploop變量聲明前加上 volatile 標志。要不然优化程序會將你的stoploop改為寄存器變量,這樣,不管你如何在主線程中改變stoploop, 子線程中的stoploop始終會為false。你的線程也就...不會結束了。


你可能感兴趣的:(C++)