进行 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。