_beginthread, _beginthreadex与CreateThread的不同

三者的声明如下:

uintptr_t _beginthread(
void( *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
HANDLE WINAPI CreateThread(
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);其实在Windows平台,创建线程只能通过调用CreatetThread来创建线程。

前二者之所以存在,是因为MS为了支持大把的C函数也不得不加入一个C运行时库,当然这个C库是需要MS重构下的。这里面最复杂就是多线程方面的事情了,因为原来的C运行库基本没有多线程的概念的。

_beginthread和_beginthreadex的除了参数的个数不同外,还有以下三点不同:

线程入口函数的调用方式不一样,前者的入口函数调用方式为__cdecl,而后者为__stdcall。二者的差别是比较明显的,且前者的入口函数没有返回值,后者有返回值。

_beginthread不支持安全属性,关于安全属性可以在网上搜索相关的知识。

_beginthreadex返回线程的句柄,函数会返回线程的句柄,这个句柄在线程退出后,需要程序员自己关闭。另外,_beginthread函数创建的线程在执行后,会自动终止。


那如何选择使用哪一个呢?

如何编写的代码中使用了C库的函数(没有调用C库函数也是有可能导入C库),那么应该使用_beginthreadex函数。另外,如果要获取创建的线程的句柄和ID,或者要以SUSPEND的方法创建线程,则需要调用_beginthreadex。

如果线程中依赖了C库而直接使用CreateThread来创建线程则会导致内存泄漏。


_beginthread相当于如下代码:(CloseHandle)(HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, NULL);
而_beginthread则可以简单的认为是“发射后不管”的线程(不需要人工调用CloseHandle来关闭线程句柄)。
而这两个函数最终都是调用CreateThread来创建线程的。



<think>我们正在讨论Windows平台下创建线程的API选择:CreateThread和_beginthreadex。根据引用内容,我们得知:1.CreateThreadWindows操作系统提供的底层API。2._beginthreadex是C/C++运行时库提供的函数,它内部会初始化线程相关的运行时库状态(如线程局部存储等),然后调用CreateThread。3.使用_beginthreadex可以确保C/C++运行时库在多线程环境下的正确性,特别是当线程中使用了运行时库函数(如malloc,printf等)时。4._beginthread是_beginthreadex的一个简化版本,但功能有限(例如不支持安全属性等),通常不推荐使用。因此,在C/C++程序(特别是使用C运行时库的程序)中,推荐使用_beginthreadex来创建线程,以避免潜在的问题(如内存泄漏或运行时库状态不一致)。使用场景对比:-CreateThread:当你不使用C/C++运行时库,或者你明确知道如何管理运行时库的线程状态(例如在纯Win32API程序中且不调用任何运行时库函数)时,可以直接使用CreateThread。-_beginthreadex:在大多数C/C++程序中,尤其是当线程中会调用标准库函数(如I/O、内存分配等)时,应该使用_beginthreadex。此外,注意线程退出时:-使用CreateThread创建的线程,在线程函数中使用ExitThread退出(但通常不显式调用,而是自然返回)。-使用_beginthreadex创建的线程,应该使用_endthreadex退出(同样,通常在线程函数返回时自动调用)。在引用[2]中给出了一个使用_beginthreadex的例子,其中线程函数返回后,系统会调用_endthreadex来清理线程相关的运行时库状态。总结:在C/C++程序中使用_beginthreadex是更安全的选择,除非有特殊原因(如性能考虑或避免运行时库依赖),否则应优先使用_beginthreadex。下面我们给出一个使用CreateThread的简单示例(注意:如果线程中使用了C运行时库函数,可能会出现问题)和一个使用_beginthreadex的示例。使用CreateThread的示例(仅用于演示,实际中不推荐在C++中使用,除非确保不使用任何C运行时库函数):```c#include<windows.h>#include<iostream>DWORDWINAPIThreadFunc(LPVOIDlpParam){//注意:如果这里使用了C运行时库函数(如printf,malloc等),可能会导致问题for(inti=0;i<5;i++){//使用Win32API输出OutputDebugStringA("Threadrunning...\n");Sleep(1000);}return0;}intmain(){HANDLEhThread=CreateThread(NULL,//默认安全属性0,//默认堆栈大小ThreadFunc,//线程函数NULL,//无参数0,//创建标志,0表示立即运行NULL//不需要线程ID);if(hThread==NULL){//处理错误return1;}//等待线程结束WaitForSingleObject(hThread,INFINITE);//关闭线程句柄CloseHandle(hThread);return0;}```使用_beginthreadex的示例(推荐):```c#include<windows.h>#include<iostream>#include<process.h>//包含_beginthreadexunsignedint__stdcallThreadFunc(void*lpParam){//这里可以安全地使用C运行时库函数for(inti=0;i<5;i++){std::cout<<"Threadrunning..."<<std::endl;Sleep(1000);}return0;}intmain(){unsignedintthreadID;HANDLEhThread=(HANDLE)_beginthreadex(NULL,//安全属性0,//堆栈大小ThreadFunc,//线程函数NULL,//参数0,//创建标志,0表示立即运行&threadID//获取线程ID);if(hThread==0){//处理错误return1;}WaitForSingleObject(hThread,INFINITE);CloseHandle(hThread);return0;}```注意:在_beginthreadex线程函数中,我们使用std::cout,这是安全的,因为_beginthreadex已经为线程初始化了C/C++运行时库的状态。最后,关于线程池,引用[3]中提到了Windows线程池API(如CreateThreadpoolWork),它提供了更高效的线程管理机制,适用于需要大量短期任务并行处理的场景。但这不是用户当前问题的重点。相关问题:1.在C++11及以上版本中,如何创建线程WindowsAPI相比有何优势?2.使用CreateThread创建线程时,如果线程函数中使用了C运行时库函数,可能会出现什么问题?3.线程退出时,为什么需要调用_endthreadex?如果不调用会怎样?4.Windows线程池API适用于哪些场景?如何使用?</think>### Windows线程创建API对比:CreateThread vs _beginthreadexWindows平台下创建线程时,`CreateThread`和`_beginthreadex`是最常用的API,但它们的使用场景和内部机制有显著差异: #### 1. **核心区别** - **`CreateThread`** 操作系统原生API(位于`Kernel32.dll`) 直接调用Windows内核创建线程 **风险**:未初始化C/C++运行时库(CRT)的线程局部存储(TLS),可能导致: - 内存泄漏(CRT未正确释放资源) - 标准库函数(如`printf`/`malloc`)崩溃 - **`_beginthreadex`** CRT提供的线程创建函数(声明于`<process.h>`) 内部流程: 1. 初始化CRT的TLS(包括`errno`、浮点状态等) 2. 调用`CreateThread`创建真实线程 3. 自动绑定`_endthreadex`清理函数 **优势**:完全兼容CRT,避免资源泄漏[^1][^2] #### 2. **使用场景对比** | **场景** | **推荐API** | **原因** | |------------------------------|---------------------|--------------------------------------------------------------------------| | 纯Win32 API程序 | `CreateThread` | 未使用CRT函数,无需额外开销 | | 使用CRT函数(如`cout`/`malloc`) | `_beginthreadex` | 确保线程安全,避免内存泄漏 | | 需要传递多个参数 | `_beginthreadex` | 支持`void*`参数传递(比`CreateThread`的`LPVOID`更灵活)[^2] | | 需要安全属性(如ACL) | `_beginthreadex` | 支持安全描述符(`_beginthread`不支持) | | 跨平台兼容性 | C++11 `std::thread` | 标准库方案(非本问题范围) | #### 3. **代码示例对比 **`CreateThread`基础用法(风险较高)** ```cpp #include <windows.h> DWORD WINAPI ThreadFunc(LPVOID param) { // 若此处使用printf/malloc可能崩溃! return 0; } int main() { HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } ``` **`_beginthreadex`推荐用法** ```cpp #include <windows.h> #include <process.h> unsigned __stdcall ThreadFunc(void* param) { // 可安全使用CRT函数 printf("Thread %d running\n", GetCurrentThreadId()); return 0; // 自动触发_endthreadex } int main() { unsigned threadId; HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, ThreadFunc, NULL, 0, &threadId ); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } ``` #### 4. **关键注意事项** 1. **线程退出** - `CreateThread`线程应返回退出码 - `_beginthreadex`线程返回时自动调用`_endthreadex`[^2] 2. **参数传递** `_beginthreadex`的`arglist`支持复杂数据结构: ```cpp struct Params { int id; const char* name; }; Params p = {1, "Thread1"}; _beginthreadex(NULL, 0, Func, &p, 0, NULL); ``` 3. **错误处理** - `CreateThread`失败返回`NULL` - `_beginthreadex`失败返回`0`(需`HANDLE`类型区分) #### 5. **性能考量** - `_beginthreadex`有轻微初始化开销(约1-2μs) - 在需要高频创建线程的场景(如游戏服务器),建议使用**线程池**(如`CreateThreadpoolWork`)替代[^3] > **总结**:在C/C++项目中,只要涉及CRT函数就应始终使用`_beginthreadex`;仅在纯Win32 API且无CRT依赖时考虑`CreateThread`。 --- ### 相关问题 1. 如何避免使用`CreateThread`导致的内存泄漏? 2. 在多线程环境中使用C标准库函数需要注意哪些线程安全问题? 3. Windows线程池(Thread Pool API)相比手动创建线程有哪些优势? 4. C++11的`std::thread`Windows原生线程API如何选择? 5. 当线程需要频繁创建销毁时,哪种线程管理策略性能最优?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值