Windows Threading: _Beginthread VS _Beginthreadex VS Createthread C++

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

_beginthread vs CreateThread

_beginthread() and _beginthreadex() was required by earlier versions of the Microsoft CRT to initialize thread-local state. The strtok() function would be an example. That's been fixed, that state now gets dynamically initialized, at least since VS2005. Using CreateThread() no longer causes problems.

Multithreading with _beginthread and CreateThread

Your call to CreateThread puts the thread ID into thHalloHandle. The call to _beginthread puts the thread handle into thHalloHandle.

Now, the thread ID is not the same as the thread handle. When you call PostThreadMessage you do need to supply a thread ID. You only do that for the CreateThread variant which I believe explains the problem.

Your code lacks error checking. Had you checked for errors on the call to PostThreadMessage you would have found that PostThreadMessage returned FALSE. Had you then gone on to call GetLastError that would have returned ERROR_INVALID_THREAD_ID. I do urge you to include proper error checking.

In order to address this you must first be more clear on the difference between thread ID and thread handle. You should give thHalloHandle a different name: thHalloThreadId perhaps. If you wish to use _beginthread you will have to call GetThreadId, passing the thread handle, to obtain the thread ID. Alternatively, use _beginthreadex which yields the thread ID, or indeed CreateThread.

Windows Threading: beginthread or QueueUserWorkItem (C++)

QUWI uses a thread from the thread pool to execute the callback function. Such threads are very light weight but not suitable for all types of threaded tasks. Basic requirements are that they need to be relatively short-lived, don't block very often and are not time critical.

It is all rather well explained in the SDK topic.

How to start a thread with _beginthreadex?

_beginthreadex(NULL, 0, ThreadFunc, NULL,0,NULL); 

should do the trick for you. You can ignore those additional parameters as most of those are optional.

The following SO links might be useful for you:

Windows threading: _beginthread vs _beginthreadex vs CreateThread C++

_beginthread vs CreateThread

How to properly use _beginthread and endthread

As stated in the comments by David Hefferman you can simply change your code back to using CreateThread. The Visual C++ runtime (CRT) will automatically initialize the CRT's per thread data the first time you use a function that uses the per thread data.

The CRT will also automatically free the per thread data when a thread ends, so using CreateThread won't cause memory leaks. There is one exception, if all of the following conditions are true then per thread data isn't automatically freed:

  • You're building an executable, not a DLL
  • You're linking against the static version of the CRT library (LIBCMT.LIB) instead of the DLL version (MSVCRT.LIB)
  • The executable you built is run under Windows XP (or an earlier version of Windows).

Note that even if all this true in your case, the memory leak isn't going to be significant unless you're creating a long lived application that creates and destroys hundreds of thousands of threads over its life time.

If you still want to use the CRTs thread creation functions (_beginthread/_beginthreadex) you should follow these guidelines:

  • Never use the handle returned by _beginthread. With _beginthread the thread handle is automatically closed when the thread exits, which can potentially happen before _beginthread even returns. You can't use it with WaitForSingleObject safely because the thread might have already exited before you call this function. If you want to use the thread handle for anything use _beginthreadex instead.
  • You should never close the handle returned by _beginthread. The CRT will do it automatically, and as described in the previous point, may do so before you have chance to.
  • You should always close the handle returned by _beginthreadex when you no longer need it. The CRT won't do this automatically for you, so it's your own responsibility.
  • Don't call _endthread or _endthreadex unless you want to quickly and abnormally terminate the thread. While the CRT will free its own per thread data, none of the C++ destructors for any of the thread's objects will be called. It behaves similarly to how _exit ends the process without calling destructors.
  • The normal means of ending a thread should be by returning from the function passed as an argument to _beginthread or _beginthreadex. This will result in C++ destructors being called as a normal part of the function return.

C++11 std::thread vs windows CreateThread

Portability

std::thread is new to C++11 standard - with it, you can write portable code in C++ across compilers supporting C++11. You can feel the future in it.

It is based on boost::thread, which supports older compilers not supporting C++11 - which makes porting to other platforms even easier.

If you need to use platform specific tricks, std::thread::native_handle is the way to go.

CreateThread is specific to WinAPI, this implies writing non-portable code. Also, this API is quite old and more inconvenient to use.

RAII

WinAPI is a C API which does not encourage modern C++ good practices. Every threading primitive you create, you must later destroy manually.

This is not the case for thread library in C++11, and this makes higher-level abstractions easier to write. While std::thread is still fairly low-level (either you .join() or .detach() your thread, or the thread destructor will terminate your program), C++11 threading library has std::lock_guard and other lock classes for supporting RAII for mutexes.

While C++11 has some higher-level abstractions, like std::async for launching functions asynchronously, it does not provide other abstractions like threadpools, so you may want to use other libraries.

Type safety

WinAPI can only call function pointers with specific signature - which is prone to bugs related to type safety, lifetime of objects and mismanaging memory.

std::thread can call any callable object:

// call free-standing function in a separate thread
std::thread first(func);

// call free-standing function with arguments (1, 2), in a separate thread
std::thread second(func, 1, 2);

// call static member function in a separate thread
std::thread third(&A::static_memfun);

// call non-static member of a temporary in a separate thread
std::thread fourth(&A::memfun, A());

//call std::function in a separate thread
std::function<void(int)> callback = std::bind(func, 1, _1);
std::thread fifth(callback, 2);

// call a function object
Functor f;
std::thread sixth(f);

TL;DR: There is no reason to use WinAPI threads as the main threading mechanism in new C++ code.

Difference between Afxbeginthread and CreateThread

For MFC programs, use AfxBeginThread.

CreateThread is raw Win32. It's incompatible with parts of the standard library.

_beginthread is part of the C standard library. It adds extra code to handle thread safety for other parts of the standard library that would be unsafe if you used CreateThread instead.

AfxBeginThread is (obviously enough) part of MFC. Along with the thread safety supported by _beginthread, it adds some (if only a few) C++ niceties.

So, you should only use CreateThread if the rest of your program is also pure, raw Win32, with no use of the standard library or MFC. If you're using MFC otherwise, you should normally use AfxBeginThread rather than CreateThread.

Using std::thread or CreateThread()?

In applications that load the CRT (as most C/C++ are) you can't use CreateThread, as per spec:

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 multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.

std::thread on the other hand will do the right thing.

Windows Threading-C++

Having thread created (such as with _beginthreadex) you need to let the thread exit gracefully as you never know if it is in the middle of something just now (having a lock on a certain resource - for instance). Still you have an option to blow it away with TerminateThread API any time.

SetThreadAffinityMask and friends let you locate your threads at the CPU battlefield. You might end up leaving OS scheduler to choose cores to run your threads on though, as chances are high that it is going to be more efficient.

Update on reusing threads: Creating a thread you are passing your thread proc to start, and as soon as you return from it, the thread is about to be terminated. That is, starting another worker thread activity is possible in two ways: either create a new thread from the start, or do not exit from thread proc and synchronize to catch up a new worker activity request. The latter might be implemented using IPC objects, e.g. events:

int ThreadProc()
{
while(true)
{
wait for new event;
if(termination requested) break;
otherwise, on worker activity request, do next requested task;
}
}

Refer to Thread Synchronization for Beginners for sample code and description.



Related Topics



Leave a reply



Submit