书籍:《Visual C++ 2017从入门到精通》

环境:Visual Studio 2022

内容:[例8.18]_beginthreadex函数的简单示例

​​1. 函数来源与用途​​

​​_beginthreadex()​​ 和 ​​_endthreadex()​​ 是 ​​C运行时库(CRT)​​ 提供的线程管理函数,用于创建和终止线程,并自动初始化与C运行时相关的资源(如线程局部存储、errno 等)。​​_beginthreadex()​​:创建并启动一个新线程,返回线程句柄。​​_endthreadex()​​:终止当前线程,释放相关资源。

​​2. 函数原型与参数​​

​​2.1 _beginthreadex()​​

uintptr_t _beginthreadex(

void *security_descriptor, // 安全属性(通常为NULL)

unsigned stack_size, // 线程栈大小(默认为1MB)

unsigned (WINAPI *start_address)(void *), // 线程入口函数

void *arglist, // 传递给线程函数的参数

unsigned initflag, // 创建标志(如CREATE_SUSPENDED)

unsigned *thrdaddr // 返回线程ID

);

​​返回值​​:线程句柄(HANDLE),失败时返回 0。​​特点​​:

自动分配线程栈空间(若 stack_size 为0)。初始化C运行时库的线程数据(如 errno、文件流、TLS)。需与 _endthreadex() 配合使用。

​​2.2 _endthreadex()​​

void _endthreadex(unsigned retcode);

​​参数​​:retcode 是线程的退出代码。​​作用​​:终止当前线程,释放资源。​​调用方式​​:通常在线程函数末尾隐式调用,也可显式调用。

​​3. 工作流程​​

​​3.1 使用 _beginthreadex() 创建线程​​

#include

unsigned __stdcall ThreadFunc(void* param) {

// 线程逻辑

_endthreadex(0); // 显式终止线程(可选)

return 0;

}

int main() {

uintptr_t hThread = _beginthreadex(NULL, 0, ThreadFunc, NULL, 0, NULL);

if (hThread == 0) {

// 错误处理

}

WaitForSingleObject((HANDLE)hThread, INFINITE); // 等待线程结束

CloseHandle((HANDLE)hThread);

return 0;

}

​​3.2 线程终止​​

​​隐式终止​​:线程函数执行完毕时,自动调用 _endthreadex()。​​显式终止​​:在任意位置调用 _endthreadex(),但需确保资源已释放。

​​4. 与 CreateThread 的区别​​

​​特性​​​​_beginthreadex()​​​​CreateThread​​​​所属库​​C运行时库(CRT)Windows API​​栈初始化​​自动分配和初始化栈需手动指定栈大小​​运行时库兼容性​​初始化CRT数据(如 errno)不初始化CRT数据​​线程局部存储(TLS)​​自动分配需手动处理​​异常处理​​支持C++异常需通过结构化异常处理(SEH)

​​5. 关键注意事项​​

​​5.1 必须配对使用​​

若使用 _beginthreadex() 创建线程,必须在线程函数中调用 _endthreadex(),否则可能导致资源泄漏(如未释放的文件句柄)。

​​5.2 栈大小管理​​

默认栈大小为1MB,可通过 stack_size 参数调整。过小的栈可能导致栈溢出,过大会浪费内存。

​​5.3 线程函数签名​​

线程函数必须符合 unsigned __stdcall (void*) 格式,返回类型为 unsigned int。

​​5.4 与C++的兼容性​​

_beginthreadex() 支持C++异常,若需使用C++异常,应优先选择此函数。

​​6. 示例代码:多线程求和​​

#include

#include

unsigned __stdcall SumThread(void* param) {

int* data = (int*)param;

unsigned int sum = 0;

for (int i = 0; i < 100; i++) {

sum += data[i];

}

printf("Sum: %u

", sum);

_endthreadex(sum); // 显式传递退出代码

return sum;

}

int main() {

int data[100];

for (int i = 0; i < 100; i++) {

data[i] = i + 1;

}

uintptr_t hThread = _beginthreadex(NULL, 0, SumThread, data, 0, NULL);

if (hThread == 0) {

printf("Failed to create thread.

");

return 1;

}

WaitForSingleObject((HANDLE)hThread, INFINITE);

CloseHandle((HANDLE)hThread);

return 0;

}

​​7. 替代方案与现代实践​​

​​推荐使用 std::thread​​:C++11及以上版本提供了跨平台的线程库,无需依赖CRT。​​使用 _beginthread()​​:若需更轻量级的线程创建(但需手动管理CRT资源)。

​​8. 总结​​

​​_beginthreadex()​​ 和 ​​_endthreadex()​​ 是CRT提供的线程管理工具,适合需要与C运行时库深度集成的项目。​​优点​​:自动初始化CRT资源(如TLS、errno),简化线程创建。​​缺点​​:功能有限,不适合复杂场景(如跨平台开发)。​​适用场景​​:Windows平台下的多线程任务,或与C标准库紧密集成的项目。

实际开发中,建议优先使用C++11的 std::thread 或Windows API的 CreateThread,以获得更好的灵活性和可维护性。