对于_beginthreadex函数有以下重点

  1) 每个线程都有自己的专用_tiddata内存块,它们是从C/C++运行库的堆(heap)上分配的。

  2)传给_beginthreadex的线程函数的地址保存在_tiddata内存块中。

  3)_beginthreadex确实会在内部调用CreateThread,因为操作系统只知道用这种方式来创建一个新线程。

  4)CreateThread函数被调用时,传给它的函数地址是_threadstartex(而非pfnStartAddr)。另外,参数地址是_tiddata结构的地址,而非pvParam。

  5)如果一切顺利,会返回线程的句柄,像CreateThread那样。任何操作失败,会返回0。

  为新线程初始化_tiddata结构之后,接着来看看这个结构如何与线程关联的:


 static   unsigned  long   WINAPI _threadstartex (void* ptd) {

                // Note: ptd is the address of this thread's tiddata block.
                // Associate the tiddata block with this thread so

                // _getptd() will be able to find it in _callthreadstartex.

              TlsSetValue(__tlsindex, ptd);
               // Save this thread ID in the _tiddata block.
               ((_ptiddata) ptd)->_tid = GetCurrentThreadId();

             // Initialize floating-point support (code not shown).

            // call helper function.
          _callthreadstartex ();
            // We never get here; the thread dies in _callthreadstartex.
           return(0L);
        }

    static void _callthreadstartex(void) {
              _ptiddata ptd; /* pointer to thread's _tiddata struct */

             // get the pointer to thread data from TLS
           ptd = _getptd();

         // Wrap desired thread function in SEH frame to
       // handle run-time errors and signal support.
    __try {
              // Call desired thread function, passing it the desired parameter.
             // Pass thread's exit code value to _endthreadex.
    _endthreadex (
              ((unsigned (WINAPI *)(void *))(((_ptiddata)ptd)->_initaddr))
               (((_ptiddata)ptd)->_initarg)) ;
    }
    __except(_XcptFilter(GetExceptionCode(), GetExceptionInformation())){

     // The C run-time's exception handler deals with run-time errors

    // and signal support; we should never get it here.

        _exit(GetExceptionCode());
      }
 }
 


  关于_threadstartex函数,要注意一下几大重点:

  1)新的线程首先执行RtlUserThreadStart(在NTDLL.dll文件中),然后再跳转到_threadstartex;

  2)_threadstartex的参数是新线程的_tiddata内存块的地址;

  3)TlsSetValue是一个操作系统函数,它将一个值与主调函数关联起来。这是所谓的线程局部存储(Thread Local Storage,TLS)。_threadstartex函数将_tiddata内存块与新建线程关联起来;

  4)在无参数的辅助函数_callthreadstartex中,有一个SEH帧,它将预期要执行的线程函数包围起来。这个帧处理着与运行库有关的许多事情—比如运行时错误;

  5)预期要执行的线程函数会被调用,并向其传递预期的参数。函数的地址和参数会被保存在TLS的_tiddata数据块中,并会在_callthreadstartex中从TLS中获取;

  6)线程函数的返回值被认为是线程的退出代码;