Windows 线程创建方式的比较

时间:2022-11-13 17:34:42

进行 Windows 编程时,常需要涉及多线程编程,以下是 Windows 提供的关于创建线程的3个API。

由于工作繁忙,还未来得及编辑完本篇博客,但是基本内容已经讲清楚,如有疑问,可自行查阅 MSDN。如再有时间,将尽快补全。

一、 函数原型

  • CreateThread
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
);
  • __beginthread
uintptr_t _beginthread(
       void( *start_address )( void * ),
       unsigned stack_size,
       void *arglist
    );
  • _beginthreadex
uintptr_t _beginthreadex(
       void *security,
       unsigned stack_size,
       unsigned ( *start_address )( void * ),
       void *arglist,
       unsigned initflag,
       unsigned *thrdaddr
    );


二、三者之间的差别

  • CreateThread 不会创建线程局部数据 tiddata,用于存储CRT运行时可能产生的错误 ( 存储在 errno 变量之间,对于多线程来说,是个全局共享变量,有数据竞争问题 )

    但是,_beginthread 和 _beginthreadex 两个函数会在真正创建一个线程之前,先创建一个线程局部资源区 tiddata。

    所以,如果线程中会使用到 CRT 运行时函数,最好不要使用 CreateThread 创建线程。因为,一旦CRT运行时函数发生异常,通过 GetLastError 获得错误码时,获得的可能是其他线程在使用CRT运行时函数所产生的错误。

  • _beginthread ,如果线程执行函数返回过快(创建函数还没有返回,线程已经执行完毕),则将导致 _beginthread 返回无效句柄。实际上,_beginthread 并不保证返回有效句柄。

    所以 _beginthread 返回的句柄不能用于 WaitForSingleObject 。

    注:WaitForSingleObject 是用于检测句柄状态的一个API,在此处可以用于线程同步。

  • _beginthreadex 可设置线程初始状态,以及是否可以继承性等安全属性。由于本函数返回的句柄 Handle 必须被调用线程关闭 CloseHandle ,所以本函数保证返回一个有效的句柄。

  • _beginthread 创建的线程执行函数,在 return 时,将自动调用 _endthread(也可以显示调用), 而且 _endthread 会主动 CloseHandle,

    所以对于_beginthread 创建的线程句柄,不需要显示的调用 CloseHandle。

  • _beginthreadex 创建的线程执行函数在 return 时,将自动调用 _endthreadex(也可以显示调用), 而 _endthreadex 并不会主动调用 CloseHandle。

    由 _beginthreadex 创建的线程句柄,必要由调用 _beginthreadex 的线程 CloseHandle ,以避免句柄泄露。

  • 主动的显式调用 ExitThread、_endthread 和 _endthreadex 会导致不会调用自动C++类的析构函数,而通过 return 返回的结束线程方式会调用C++类的析构函数

    所以通过 return 来结束一个线程吧。

  • 创建线程时,_beginthread 和 _beginthreadex 都可以使用,但是 _beginthread 返回的 Handle 不能通过 WaitForSingleObject 来同步主辅线程。

    因为,_beginthread 创建的线程在返回时,会主动调用 CloseHanlde ,所以,如果线程返回过快,就会导致 WaitForSingleObject 无法检测句柄状态(Handle)。

    以下这段英文摘自 MSDN:

    _endthread calls CloseHandle, destroying the thread object before it can be set to the signaled state ,
    

    所以 WaitForSingleObject , 所以是无法检测到 由 _beginthread 返回的 Handle 的状态的。

综上所述,创建线程的时候,最好不要使用 CreateThread 和 _beginthread 。而尽量使用 _beginthreadex。