Windows threading: _beginthread vs _beginthreadex vs CreateThread C++
Asked Answered
D

17

142

What's a better way to start a thread, _beginthread, _beginthreadx or CreateThread?

I'm trying to determine what are the advantages/disadvantages of _beginthread, _beginthreadex and CreateThread. All of these functions return a thread handle to a newly created thread, I already know that CreateThread provides a little extra information when an error occurs (it can be checked by calling GetLastError)... but what are some things I should consider when I'm using these functions?

I'm working with a windows application, so cross-platform compatibility is already out of the question.

I have gone through the msdn documentation and I just can't understand, for example, why anybody would decide to use _beginthread instead of CreateThread or vice versa.

Cheers!

Update: OK, thanks for all the info, 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? What's the deal there?

Derosa answered 1/12, 2008 at 17:20 Comment(1)
Here is an analysis of what _beginthreadex() does for C/C++ programmers that I found from a link on Eli Bendersky's website. This is from a Q&A on whether to use CreateThread() or not. microsoft.com/msj/0799/win32/win320799.aspxAustria
E
102

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).

Eelpout answered 1/12, 2008 at 17:29 Comment(13)
@Mike B - good point. I never knew that, but then I always use _beginthreadex.Sum
This is no longer quite as true as it used to be. The CRT will function correctly in a thread created by CreateThread() with the exception of he signal() function. There will be a small memory leak (~80 bytes) for each thread created with CreateThread() that uses the CRT, but it will function correctly. See for more info: support.microsoft.com/default.aspx/kb/104641Antimony
But why does it start with an underscore then?Parke
@John: Actually that bug applies only up to MSVC++ 6.0Parke
@bobobobo: Good question. I can only speculate that MS originally intended the _begin routines to be internal calls and CreateThread was supposed to be the API function everyone would call. Another potential explanation is that MS has a long & glorious history of ignoring the standard & making very bad decisions about naming things.Antimony
@bobobobo: See the link I provided in my comments (I'll edit the post). It agrees with you that the original premise of my post only applies to VC6 and below.Antimony
The _begin functions start with an underscore because Microsoft started to follow the standard more closely. In the C runtime, names that being with underscore are reserved for the implementation (and the implementation can document them for end-user use, as with these). beginthreadex() is a name that is permitted for the user to use. If the C runtime used it, then it might conflict with a end-user symbol that the user had legitimate right to be able to expect to use. Note that Win32 APIs are not part of the C runtime, and they use the user's namespace.Drusilla
There is no difference anymore between the both. All comments about memory leaks etc are based on very old < VS2005 versions.Whereas
@Lothar: There are differences between the Win32 API call CreateThread and the CRT calls _beginthread/ex, and when calling the CRT on a thread, it should always be created with _beginthread/ex. There may no longer be memory leaks, if you don't. But you surely won't get your floating point environment properly initialized when calling CreateThread, for example. There's more: "If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions."Twelfthtide
@Lothar: CreateThread is part of kernel32.dll (a DLL that all processes have already loaded into memory by the time any user DLLs are brought in), it is among a very small set of functions that are safe to call from DllMain (...). _beginthreadex offers no guarantee of safety and I would imagine the fact that it implicitly requires the Visual C++ runtime to be initialized will be the source of deadlocks if you attempt to do this from DllMain.Unanimous
@AndonM.Coleman This MSDN article on DllMain best practices says to not call CreateThread within DllMain. Also, for what it's worth, I can't reproduce a memory leak in VS 2015 with CreateThread. Obviously, if you plan to use the CRT, you will want to use _beginthreadex anyway.Rubinrubina
It does say that, but it's qualified with the caveat that you do not wait on the thread. DllMain holds a loader lock, and the last thing you want to do is deadlock. Threads started from DllMain start in suspended state and wake up after all the other DLLs finish.Unanimous
@AndonM.Coleman: "Threads started from DllMain start in suspended state and wake up after all the other DLLs finish." - I don't think that's accurate. Threads started from DllMain start like any other thread. Except, they do have to wait on the loader lock, so the system can call DllMain with DLL_THREAD_ATTACH. That's why you deadlock when you wait on threads created in DllMain, not because they start in suspended state.Twelfthtide
D
39

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.

Drusilla answered 1/12, 2008 at 18:35 Comment(5)
There are appropriate times when CreateThread() is warranted, but honestly you really have to go out of your way to do it. We're talking a complete lack of anything portable and writing an exclusively WIN32 API DLL or App. Including no C-runtime calls. Even STL usage is limited in that you have to provide custom allocators to use WIN32 memory management functions. The setup to do this with Developer Studio is a job in itself, but for an only-ever-WIN32 lib with the smallest possible footprint, it can be done. But yeah, it ain't bloody likely for almost all but a very select few.Vocalist
@WhozCraig: There are more severe limitations when omitting the CRT. The most prominent ones being: No 64-bit integer support, no floating point support, and - most drastically - no exception handling. This really means no exception handling -- at all. Not even SEH exceptions. This is particularly tough to make up for, and chances for calling CreateThread being the Right Thing are diminishingly slim.Twelfthtide
@MichaelBurr: You may want to update your answer for VC++ 2015.Kaufman
@Mehrdad: Which changes specifically do you find worth mentioning?Twelfthtide
I have found that DisableThreadLibraryCalls has no effect on threads created with CreateThread, but does disable threads created with _beginthread or _beginthreadex.Zosema
A
26

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.

Agueda answered 19/10, 2012 at 0:1 Comment(3)
Great starting point. With a little debugging one can show the __CRTDLL_INIT is called even for a statically linked CRT. Callstack the init is called from _LdrpCallInitRoutine@16(), I am not sure exactly by what mechanism. This means with recent CRT the all initialization / deinitialization is done correctly with the exception of signal handling, which is still done in the _threadstartex helper function called from beginthread, but not from CreateThread. Perhaps you could add this into the answer and I will award the bounty?Tinatinamou
Bounty awarded, as this seems most helpful. Still, the answer perhaps might be worth updating. If you cannot do it, I might revisit it within a few days.Tinatinamou
@MSN: Please be aware, that CreateThread is still bad in a DLL, if you are linking agains the static CRT and have called DisableThreadLibraryCalls which disables the calls for DLL_THREAD_DETACH. Then you will get memory leaks. This is documented here in my KB article: support.microsoft.com/kb/555563/en-usThayne
L
17

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.

Loyceloyd answered 1/12, 2008 at 18:33 Comment(0)
C
14

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.

Coastwise answered 12/4, 2011 at 11:44 Comment(0)
S
9

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().

Spondylitis answered 1/12, 2008 at 18:21 Comment(5)
1999 article, may since have been fixedParke
This article from 2005 still confirms that there is a problem.Spondylitis
Yeah, it only applies to MSVC++ 6.0 Service Pack 5 and earlier. (see "Applies to" expandable dropdown). This is not an issue today if you are using VC7 or above.Parke
This is still an issue, if you link agains the static CRT! Also it is still a problem if you call DisableThreadLibraryCalls in a DLL which is statically linked; see my KB article: support.microsoft.com/kb/555563/en-usThayne
You misrepresented the information: CreateThread does not ever leak memory. It is rather the CRT that does, when called from a thread that hasn't been properly initialized.Twelfthtide
D
6

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.

Drusilla answered 1/12, 2008 at 19:35 Comment(0)
P
5

Looking at the function signatures, CreateThread is almost identical to _beginthreadex.

_beginthread, _beginthreadx vs CreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

The remarks on here say _beginthread can use either __cdecl or __clrcall calling convention as start point, and _beginthreadex can use either __stdcall or __clrcall for start point.

I think any comments people made on memory leaks in CreateThread are over a decade old and should probably be ignored.

Interestingly, both _beginthread* functions actually call CreateThread under the hood, in C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src on my machine.

// From ~line 180 of beginthreadex.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;
}
Parke answered 2/6, 2011 at 20:44 Comment(1)
Comment, on why you should not call CreateThread and mix in CRT calls on that thread (definitely not a decade old, and definitely should not be ignored): "If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions."Twelfthtide
A
3

beginthreadex gives you a thread HANDLE for use in WaitForSingleObject and friends. beginthread doesn't. Don't forget to CloseHandle() when you are done. The real answer would be to use boost::thread or soon C++09's thread class.

Aronson answered 1/12, 2008 at 18:32 Comment(2)
The msdn description says that "If successful, each of these functions returns a handle to the newly created thread;" referring to _beginthread() and _beginthreadex()...Derosa
@Kiril: but then the documentation goes on to say that _beginthread closes the handle for you, meaning that you can't use it if the thread exits quickly...Sum
C
3

CreateThread() once was a no-no because the CRT would be incorrectly initialize/clean up. But this is now history: One can now (using VS2010 and probably a few versions back) call CreateThread() without breaking the CRT.

Here is the official MS confirmation. It states one exception:

Actually, the only function that should not be used in a thread created with CreateThread() is the signal() function.

However, from consistence point of view, I personally prefer to keep using _beginthreadex().

Crocker answered 12/10, 2012 at 12:14 Comment(5)
While I suppose this to be true, can you provide some authoritative evidence - either by linking to MS Documentation, or by analysing the CRT _beginthreadex / _endthreadex sources?Tinatinamou
@Suma, I guess I added the MS link it while you were typing your comment ;-)Crocker
The document you are linking to does not seem to confirm: "However, depending on what CRT functions are called, there may be a small memory leak when threads are terminated.". This means it is no longer a big and general no-no, but still a no-no if you are creating threads frequently and using those functions in them. However, the document is from 2005 and therefore cannot address the recent state of the matter.Tinatinamou
Hmm ... although it might depend on the use case, a function leaving a memory leak, no matter which size, I'd consider a no-no ... - in particular if there is a non-leaking alternative!Graphomotor
"One can now call CreateThread() without breaking the CRT." - Unfortunately, this is not true, and never has been. From CreateThread: "A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management [...] If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions."Twelfthtide
S
2

Compared to _beginthread, with _beginthreadex you can:

  1. Specify security attributes.
  2. Start a thread in suspended state.
  3. You can get the thread id which can be used with OpenThread.
  4. The thread handle returned is guaranteed to be valid if the call was successful. There for you need to close the handle with CloseHandle.
  5. The thread handle returned can be used with synchronization APIs.

The _beginthreadex closely resembles CreateThread, but the former is a CRT implementation and the latter a Windows API call. The documentation for CreateThread contains the following recommendation:

A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multi-threaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.

Sternforemost answered 23/9, 2011 at 10:17 Comment(2)
According to the API specification, bullet points 3-5 are not unique to _beginthreadex. You can cast the uintptr_t return from both functions to HANDLE.Unanimous
Yes, you are right in theory. In practice, the difference is that _beginthread closes the handle on exit. So you cannot reliably use the handle with synchronization API's or to get the thread id until and unless you use another way to synchronize and duplicate the handle. But then there is _beginthreadex doing it for you.Sternforemost
P
2

CreateThread() is Windows API call that is language neutral. It just creates OS object - thread and returns HANDLE to this thread. All windows applications are using this call to create threads. All languages avoids direct API call for obvious reasons: 1. You don't want your code be OS specific 2. You need to do some house keeping before calling API-like: convert parameters and results, allocate temporary storage etc.

_beginthreadex() is C wrapper around CreateThread() that accounts for C specific. It enables original single threaded C f-ns work in multithreaded environment by allocating thread specific storage.

If you don't use CRT you cannot avoid a direct call to CreateThread(). If you use CRT, you must use _beginthreadex() or some CRT string f-ns may not work properly prior VC2005.

Preposition answered 15/5, 2012 at 17:50 Comment(0)
L
2

CreateThread() is the straight system call. It's implemented on Kernel32.dll which, most probably, your application will already be linked against for other reasons. It is always available in modern Windows systems.

_beginthread() and _beginthreadex() are wrapper functions in the Microsoft C Runtime (msvcrt.dll). The differences between the two calls are stated in the documentation. It is thus available when the Microsoft C Runtime is available, or if your application is linked statically against it. You'll likely be linking against that library, too, unless you're coding in pure Windows API (as I personally often do).

Your question is a coherent and actually a recurrent one. As many APIs, there are duplicate and ambiguous functionality in the Windows API we have to deal with. Worst of all, the documentation does not clarify the issue. I suppose that the _beginthread() family of functions was created for better integration with other standard C functionalities, such as the manipulation of errno. _beginthread() thus integrates better with the C runtime.

Despite that, unless you have good reasons for using _beginthread() or _beginthreadex(), you should use CreateThread(), mostly because you might get one less library dependency in your final executable (and for MS CRT this does matter a bit). You also have no wrapping code around the call, although this effect is negligible. In other words, I believe that the main reason for sticking with CreateThread() is that there is no good reason to use _beginthreadex() to begin with. The functionalities are precisely, or almost, the same.

One good reason to use _beginthread() would be (as it seems to be false) that C++ objects would be properly unwinded/destroyed if _endthread() was called.

Lorca answered 18/10, 2012 at 12:51 Comment(2)
There are no ambiguous function calls at all. CreateThread is the Windows API call to create a thread. If you are using the CRT (because you are programming in C or C++), you should create threads using the CRT's _beginthread[ex] calls (which call CreateThread in addition to performing necessary CRT initialization). The most important difference between _beginthread and the ex-variant: The former retains ownership of the native thread handle, while the latter passes ownership to the caller.Twelfthtide
Nitpick: msvcrt.dll is not the C runtime DLL! See blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273Rica
M
1

If you read the book Debugging Windows Application From Jeffrey Richter in it he explains that almost in all instances you must call _beginthreadex instead of calling CreateThread. _beginthread is just a simplified wrapper around _beginthreadex.

_beginthreadex initializes certain CRT (C RunTime) internals that the CreateThread API would not do.

A consequence if you use the CreateThread API instead of using _begingthreadex calls to CRT functions might unexpected cause issues.

Check out this old Microsoft Journal From Richter.

Marshall answered 15/2, 2014 at 20:41 Comment(0)
U
0

The other answers fail to discuss the implications of calling a C run-time function that wraps a Win32 API function. This is important when considering DLL loader locking behavior.

Whether or not _beginthread{ex} does any special C Runtime thread/fiber memory management as the other answers discuss, it is implemented in (assuming dynamic linking to the C run-time) a DLL that processes may not have loaded yet.

It is not safe to call _beginthread* from DllMain. I have tested this by writing a DLL loaded using the Windows "AppInit_DLLs" feature. Calling _beginthreadex (...) instead of CreateThread (...) causes a LOT of important parts of Windows to stop functioning during bootup as the DllMain entry-point deadlocks waiting for the loader lock to be released in order to perform certain initialization tasks.

Incidentally, this is also why kernel32.dll has a lot of overlapping string functions that the C run-time also does -- use those from DllMain to avoid the same sort of situation.

Unanimous answered 16/9, 2016 at 7:15 Comment(0)
W
-2

There is no difference anymore between the both.

All comments about memory leaks etc are based on very old < VS2005 versions. I've done some stress testing years ago and could debunk this myth. Even Microsoft mixes the styles in their examples, almost never using _beginthread.

Whereas answered 4/5, 2015 at 4:42 Comment(5)
CreateThread: "If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions."Twelfthtide
Based on the subsentence "requires the use of the multithreaded version of the CRT" i assume this is documentation garbage as there is no multithreaded crt version anymore and for many years now.Whereas
"there is no multithreaded crt version anymore" - The MSDN claims that "[t]he single-threaded CRT is no longer available." You cannot both be right. I'll go with the MSDN here, too.Twelfthtide
It was a typo, of course i meant that the single threaded is gone and the multithreaded has become the standard and what is gone is the distinction between using or not using threads.Whereas
This is really getting strange. You are now using a statement, that's undoubtedly correct ("requires the use of the multithreaded version of the CRT") to claim that both this statement as well as the remainder of the documentation is very likely wrong? That sure doesn't sound right.Twelfthtide
R
-2

You should try this code

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<process.h>

UINT __stdcall Staff(PVOID lp){
 printf("The Number is %d\n", GetCurrentThreadId());
 return 0;
}

INT main(INT argc, PCHAR argv[])
{

    const INT Staff_Number = 5;
    HANDLE hd[Staff_Number];
    for(INT i=0; i < Staff_Number; i++){
       hd[i] = (HANDLE)_beginthreadex(NULL, 0, Staff, NULL, 0, NULL);
    }

 WaitForMultipleObjects(Staff_Number, Staff, TRUE, NULL);
 for(INT i=0; i < Staff_Number; i++)
 {
     CloseHandle(hd[i]);
 }
 system("pause");
 return 0;
}

if you use _beginthread instead of _beginthreadex it will give error too many argument for _beginthread it is because _beginthread couldnt create a thread with security attribute and also i think _beginthread is unnecessary you can absolutely use *(_beginthreadex) and CreateThread

Reisman answered 8/8, 2020 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.