CreateThread与_beginthreadex

作者在 2008-09-09 23:40:56 发布以下内容
    CreateThread函数是用来创建线程的Windows函数。不过,如果你正在编写C/C++代码,决不应该调用CreateThread。相反, 应该使用Visual C++运行期库函数_beginthreadex。如果不使用Microsoft的Visual C++编译器,你的编译器供应商有它自己的CreateThred替代函数。不管这个替代函数是什么,你都必须使用。"
"_beginthreadex函数的参数列表与CreateThread函数的参数列表是相同的,但是参数名和类型并不完全相同。这是因为 Microsoft的C/C++运行期库的开发小组认为, C/C++运行期函数不应该对Windows数据类型有任何依赖。_beginthreadex函数也像CreateThread那样,返回新创建的线程 的句柄。因此,如果调用源代码中的CreateThread,就很容易用对_beginthreadex的调用全局取代所有这些调用。不过,由于数据类型 并不完全相同,所以必须进行某种转换,使编译器运行得顺利些。"
"下面是关于_beginthreadex的一些要点:
• 每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件中的Visual C++源代码中)。
• 传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。
• _beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的唯一方法。
• 当调用CreatetThread时,它被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新线程。还有,传递给线程函数的参数是tiddata结构而不是pvParam的地址。
• 如果一切顺利,就会像CreateThread那样返回线程句柄。如果任何操作失败了,便返回NULL。"
"也许你想知道,如果调用CreateThread,而不是调用C/C++运行期库的_beginthreadex来创建新线程,将会发生什么情况。当一 个线程调用要求tiddata结构的C/C++运行期库函数时,将会发生下面的一些情况(大多数C/C++运行期库函数都是线程安全函数,不需要该结 构)。首先,C/C++运行期库函数试图(通过调用TlsGetValue)获取线程的数据块的地址。如果返回NULL作为tiddata块的地址,调用 线程就不拥有与该地址相关的tiddata块。这时,C/C++运行期库函数就在现场为调用线程分配一个tiddata块,并对它进行初始化。然后该 tiddata块(通过TlsSetValue)与线程相关联。此时,只要线程在运行,该tiddata将与线程待在一起。这时,C/C++运行期库函数 就可以使用线程的tiddata块,而且将来被调用的所有C/C++运行期函数也能使用tiddata块。
  当然,这看来有些奇怪,因为线程运行时几乎没有任何障碍。不过,实际上还是存在一些问题。首先,如果线程使用C/C++运行期库的signal函数,那么 整个进程就会终止运行,因为结构化异常处理帧尚未准备好。第二,如果不是调用_endthreadex来终止线程的运行,那么数据块就不会被撤消,内存泄 漏就会出现(那么谁还为使用CreateThread函数创建的线程来调用_endthreadex呢?)。
  注意如果程序模块链接到多线程DLL版本的C/C++运行期库,那么当线程终止运行并释放tiddata块(如果已经分配了tiddata块的话)时,该 运行期库会收到一个DLL_THREAD_DETACH通知。尽管这可以防止tiddata块的泄漏,但是强烈建议使用_beginthreadex而不 是使用Createthread来创建线程。
编程杂记 | 阅读 19854 次
文章评论,共1条
tangbin200
2010-05-29 09:52
1
学习了,虽然看得还不是很明白
游客请输入验证码