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 thread
2) 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.
This is the code at the core of _beginthreadex
(see crt\src\threadex.c
):
/*
* Create the new thread using the parameters supplied by the caller.
*/
if ( (thdl = (uintptr_t)
CreateThread( (LPSECURITY_ATTRIBUTES)security,
stacksize,
_threadstartex,
(LPVOID)ptd,
createflag,
(LPDWORD)thrdaddr))
== (uintptr_t)0 )
{
err = GetLastError();
goto error_return;
}
The rest of _beginthreadex
initializes per-thread data structure for CRT.
The advantage of using _beginthread*
is that your CRT calls from thread will work correctly.
You should use _beginthread
or _beginthreadex
to allow the C runtime library to do it's own initialization of the thread. Only C/C++ programmers need to know this as they should now the rules of using their own development environment.
If you use _beginthread
you do not need to call CloseHandle
as the RTL will do for you. This is why you cannot wait on the handle if you have used _beginthread
. Also _beginthread
leads to confusion if the thread function exits immediately (quickly) as the launching thread my be left holding an invalid thread handle to the thread it just launched.
_beginthreadex
handles can be used for wait but also require an explicit call to CloseHandle
. This is part of what makes them safe for using with wait. There other issue to make it completely foolproof is to always start the thread suspended. Check for success, record handle etc. The resume thread. This is required to prevent a thread from terminating before the launching thread can record its handle.
Best practice is to use _beginthreadex
, start suspended then resume after recording handle, wait on handle is OK, CloseHandle
must be called.
CreateThread()
used to have memory leaks when you use any CRT functions in your code. _beginthreadex()
has same parameters as CreateThread()
and it's more versatile than _beginthread()
. So I recommend you use _beginthreadex()
.
Regarding your updated question: "I've also read in a couple of places that I can't call WaitForSingleObject()
if I used _beginthread()
, but if I call _endthread()
in the thread shouldn't that work?"
In general, you can pass a thread handle to WaitForSingleObject()
(or other APIs that wait on object handles) to block until the thread has completed. But the thread handle created by _beginthread()
is closed when _endthread()
is called (which can be done explicitly or is done implicitly by the run time when the thread procedure returns).
The problem is called out in the documentation for WaitForSingleObject()
:
If this handle is closed while the wait is still pending, the function's behavior is undefined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With