【C/C++】CreateThread 与 _beginthreadex, 应该使用哪一个?为什么?

时间:2024-11-09 08:45:56

在 Windows 平台上进行多线程编程时,CreateThread_beginthreadex 是两种我们常用的创建线程的方法。它们都用于启动新的执行线程,但它们之间存在一些关键的区别,特别是在与 C 运行时库(CRT)的交互方面。

CreateThread

  • 低级 APICreateThread 是 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 支持。