再来看看_endthreadex:


void __cdecl _endthreadex (unsigned retcode) {
    _ptiddata ptd; // Pointer to thread's data block

    // Clean up floating-point support (code not shown).
    // Get the address of this thread's tiddata block.
    ptd = _getptd_noexit ();


    // Free the tiddata block.
    if (ptd != NULL)
        _freeptd(ptd);
    // Terminate the thread.
    ExitThread(retcode);
    }
 


  对于_endthreadex函数,要注意一下几点:

  1)C运行库的_getptd_noexit函数在内部调用操作系统的TlsGetValue函数,后者获取主调函数的tiddata内存块的地址;

  2)然后_endthreadex将此数据块释放,并调用操作系统的ExitThread函数来实际地销毁线程。它会传递并正确设置退出代码;

  我们应该避免使用ExitThread函数,因为此函数会“杀死”主调线程,而且不允许它从当前执行的函数返回。由于函数没有返回,所以构造的任何C++对象都不会被析构;它还会阻止线程的_tiddata内存块被释放,使应用程序出现内存泄露(直到整个进程终止)。

  我们应该尽量用C/C++运行库函数(_beginthreadex,_endthreadex)而尽量避免使用操作系统提供的函数(CreateThread,ExitThread)。

  十一、担心伪句柄

  HANDLE GetCurrentProcess();
  HANDLE GetCurrentThread();

  这两个函数返回到主调函数的进程内核对象或线程内核对象的一个伪句柄。它们不会再主调进程的句柄表中新建句柄。即返回的句柄并不在进程句柄表中有实际的表项,也不会影响进程内核对象或线程内核对象的使用计数。如果嗲用CloseHandle函数,并传入一个“伪句柄”,CloseHandle只是简单的忽略此调用。

  将伪句柄转换为真正的句柄,DuplicateHandle函数可以执行这个转换,如在进程句柄表中创建线程内核句柄:


<SPAN style="FONT-SIZE: 14px">    DuplicateHandle(
           GetCurrentProcess(),     // Handle of process that thread
                                                // pseudohandle is relative to
           GetCurrentThread(),    // Parent thread's pseudohandle
           GetCurrentProcess(),  // Handle of process that the new, real,
                                                // thread handle is relative to
            &hThreadParent,        // Will receive the new, real, handle
                                             // identifying the parent thread
            0, // Ignored due to DUPLICATE_SAME_ACCESS
            FALSE, // New thread handle is not inheritable
            DUPLICATE_SAME_ACCESS); // New thread handle has same </SPAN>