Windows threading: _beginthread vs _beginthreadex vs CreateThread C++ Windows threading: _beginthread vs _beginthreadex vs CreateThread C++ multithreading multithreading

Windows threading: _beginthread vs _beginthreadex vs CreateThread C++


CreateThread() is a raw Win32 API call for creating another thread of control at the kernel level.

_beginthread() & _beginthreadex() are C runtime library calls that call CreateThread() behind the scenes. Once CreateThread() has returned, _beginthread/ex() takes care of additional bookkeeping to make the C runtime library usable & consistent in the new thread.

In C++ you should almost certainly use _beginthreadex() unless you won't be linking to the C runtime library at all (aka MSVCRT*.dll/.lib).


There are several differences between _beginthread() and _beginthreadex(). _beginthreadex() was made to act more like CreateThread() (in both parameters and how it behaves).

As Drew Hall mentions, if you're using the C/C++ runtime, you must use _beginthread()/_beginthreadex() instead of CreateThread() so that the runtime has a chance to perform it's own thread initialization (setting up thread local storage, etc.).

In practice, this means that CreateThread() should pretty much never be used directly by your code.

The MSDN documents for _beginthread()/_beginthreadex() have quite a bit of detail on the differences - one of the more important is that since the thread handle for a thread created by _beginthread() gets closed automatically by the CRT when the thread exits, "if the thread generated by _beginthread exits quickly, the handle returned to the caller of _beginthread might be invalid or, worse, point to another thread".

Here is what the comments for _beginthreadex() in the CRT source have to say:

Differences between _beginthread/_endthread and the "ex" versions:1)  _beginthreadex takes the 3 extra parameters to CreateThread  which are lacking in _beginthread():    A) security descriptor for the new thread    B) initial thread state (running/asleep)    C) pointer to return ID of newly created thread2)  The routine passed to _beginthread() must be __cdecl and has  no return code, but the routine passed to _beginthreadex()  must be __stdcall and returns a thread exit code.  _endthread  likewise takes no parameter and calls ExitThread() with a  parameter of zero, but _endthreadex() takes a parameter as  thread exit code.3)  _endthread implicitly closes the handle to the thread, but  _endthreadex does not!4)  _beginthread returns -1 for failure, _beginthreadex returns  0 for failure (just like CreateThread).

Update Jan 2013:

The CRT for VS 2012 has an additional bit of initialization performed in _beginthreadex(): if the process is a "packaged app" (if something useful is returned from GetCurrentPackageId()) the runtime will initialize the MTA on the newly created thread.


In general, the correct thing to do is to call _beginthread()/_endthread() (or the ex() variants). However, if you use the CRT as a .dll, the CRT state will be properly initialized and destroyed as the CRT's DllMain will be called with DLL_THREAD_ATTACH and DLL_THREAD_DETACH when calling CreateThread() and ExitThread() or returning, respectively.

The DllMain code for the CRT can be found in the install directory for VS under VC\crt\src\crtlib.c.