在 Windows 平台上进行多线程编程时,CreateThread
和 _beginthreadex
是两种我们常用的创建线程的方法。它们都用于启动新的执行线程,但它们之间存在一些关键的区别,特别是在与 C 运行时库(CRT)的交互方面。
CreateThread
-
低级 API:
CreateThread
是 Windows API 提供的一个函数,用于创建新的线程。它是操作系统级别的函数,不涉及 C 运行时库。 -
CRT 初始化问题:直接使用
CreateThread
启动的线程不会正确初始化 C 运行时库。这意味着如果你的线程函数中使用了任何 CRT 函数(如malloc
,free
,printf
等),可能会导致不可预测的行为或内存泄漏。 -
简单性:由于
CreateThread
是操作系统级别的函数,它提供了更直接和简单的线程创建方式,但缺乏与 CRT 的集成。
_beginthreadex
-
CRT 友好:
_beginthreadex
是 C 运行时库提供的一个函数,用于创建新的线程。它内部调用了CreateThread
,但在此之前会执行一些必要的 CRT 初始化工作。 -
正确初始化:使用
_beginthreadex
创建的线程会正确初始化 C 运行时库,确保所有 CRT 函数在多线程环境中的安全使用。 -
推荐使用:对于需要使用 CRT 函数的应用程序,推荐使用
_beginthreadex
而不是CreateThread
,以避免潜在的 CRT 相关问题。
接下来是 DEMO
使用 CreateThread
#include <windows.h>
#include <stdio.h>
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
printf("Thread is running.\n");
return 0;
}
int main() {
HANDLE hThread = CreateThread(
NULL, // 默认安全属性
0, // 默认堆栈大小
ThreadFunc, // 线程函数
NULL, // 线程参数
0, // 默认创建标志
NULL); // 不需要线程标识符
if (hThread == NULL) {
printf("CreateThread failed (%d)\n", GetLastError());
return 1;
}
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
// 关闭线程句柄
CloseHandle(hThread);
return 0;
}
使用 _beginthreadex
#include <windows.h>
#include <process.h> // For _beginthreadex
#include <stdio.h>
unsigned __stdcall ThreadFunc(void* lpParam) {
printf("Thread is running.\n");
return 0;
}
int main() {
HANDLE hThread = (HANDLE)_beginthreadex(
NULL, // 默认安全属性
0, // 默认堆栈大小
ThreadFunc, // 线程函数
NULL, // 线程参数
0, // 默认创建标志
NULL); // 不需要线程标识符
if (hThread == NULL) {
printf("_beginthreadex failed\n");
return 1;
}
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
// 关闭线程句柄
CloseHandle(hThread);
return 0;
}
总结下以上的内容
-
兼容性:如果我们应用程序大量使用 CRT 函数,建议使用
_beginthreadex
来创建线程,以确保 CRT 的正确初始化和线程安全。 -
性能:对于不涉及 CRT 函数的简单线程,
CreateThread
可能稍微快一些,因为它绕过了 CRT 相关的初始化。 -
推荐实践:为了代码的安全性和可维护性,推荐使用
_beginthreadex
或 C++11 及以后的std::thread
,它们提供了更好的线程管理和 CRT 支持。