Export (0) Print
Expand All
Expand Minimize
This topic has not yet been rated - Rate this topic

_beginthread, _beginthreadex

Creates a thread.

Important note Important

This API cannot be used in applications that execute in the Windows Runtime or are compiled by using the clr:pure switch. For more information, see CRT functions not supported with /ZW.

uintptr_t _beginthread( // NATIVE CODE
   void( __cdecl *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
uintptr_t _beginthread( // MANAGED CODE
   void( __clrcall *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
uintptr_t _beginthreadex( // NATIVE CODE
   void *security,
   unsigned stack_size,
   unsigned ( __stdcall *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
uintptr_t _beginthreadex( // MANAGED CODE
   void *security,
   unsigned stack_size,
   unsigned ( __clrcall *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 

Start address of a routine that begins execution of a new thread. For _beginthread, the calling convention is either __cdecl (for native code) or __clrcall (for managed code); for _beginthreadex, it is either __stdcall (for native code) or __clrcall (for managed code).


Stack size for a new thread, or 0.


Argument list to be passed to a new thread, or NULL.


Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If Security is NULL, the handle cannot be inherited. Must be NULL for Windows 95 applications.




Points to a 32-bit variable that receives the thread identifier. If it's NULL, it's not used.

If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly, _beginthread might not return a valid handle. (See the discussion in the Remarks section.) On an error, _beginthread returns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). On an error, _beginthreadex returns 0, and errno and _doserrno are set.


For more information about these and other return codes, see errno, _doserrno, _sys_errlist, and _sys_nerr.

For more information about uintptr_t, see Standard Types.

The _beginthread function creates a thread that begins execution of a routine at start_address. The routine at start_address must use the __cdecl (for native code) or __clrcall (for managed code) calling convention and should have no return value. When the thread returns from that routine, it is terminated automatically. For more information about threads, see Multithreading Support for Older Code (Visual C++).


  • _beginthreadex has three additional parameters: initflag, security, and threadaddr. The new thread can be created in a suspended state, with a specified security (Windows NT only), and can be accessed by using thrdaddr, which is the thread identifier.

  • The routine at start_address that's passed to _beginthreadex must use the __stdcall (for native code) or __clrcall (for managed code) calling convention and must return a thread exit code.

  • _beginthreadex returns 0 on failure, rather than -1L.

  • A thread that's created by using _beginthreadex is terminated by a call to _endthreadex.

The _beginthreadex function gives you more control over how the thread is created than _beginthread does. The _endthreadex function is also more flexible. For example, with _beginthreadex, you can use security information, set the initial state of the thread (running or suspended), and get the thread identifier of the newly created thread. You can also use the thread handle that's returned by _beginthreadex with the synchronization APIs, which you cannot do with _beginthread.

It's safer to use _beginthreadex than _beginthread. If the thread that's generated by _beginthread exits quickly, the handle that's returned to the caller of _beginthread might be invalid or point to another thread. However, the handle that's returned by _beginthreadex has to be closed by the caller of _beginthreadex, so it is guaranteed to be a valid handle if _beginthreadex did not return an error.

You can call _endthread or _endthreadex explicitly to terminate a thread; however, _endthread or _endthreadex is called automatically when the thread returns from the routine that's passed as a parameter. Terminating a thread with a call to _endthread or _endthreadex helps ensure correct recovery of resources that are allocated for the thread.

_endthread automatically closes the thread handle, whereas _endthreadex does not. Therefore, when you use _beginthread and _endthread, do not explicitly close the thread handle by calling the Win32 CloseHandle API. This behavior differs from the Win32 ExitThread API.

Note Note

For an executable file linked with Libcmt.lib, do not call the Win32 ExitThread API so that you don't prevent the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.

The operating system handles the allocation of the stack when either _beginthread or _beginthreadex is called; you don't have to pass the address of the thread stack to either of these functions. In addition, the stack_size argument can be 0, in which case the operating system uses the same value as the stack that's specified for the main thread.

arglist is a parameter to be passed to the newly created thread. Typically, it is the address of a data item, such as a character string. arglist can be NULL if it is not needed, but _beginthread and _beginthreadex must be given some value to pass to the new thread. All threads are terminated if any thread calls abort, exit, _exit, or ExitProcess.

The locale of the new thread is inherited from its parent thread. If per-thread locale is enabled by a call to _configthreadlocale (either globally or for new threads only), the thread can change its locale independently from its parent by calling setlocale or _wsetlocale. For more information, see Locale.

For mixed and pure code, _beginthread and _beginthreadex each have two overloads—one takes a native calling-convention function pointer, the other takes a __clrcall function pointer. The first overload is not application domain-safe and never will be. If you are writing mixed or pure code you must ensure that the new thread enters the correct application domain before it accesses managed resources. You can do this, for example, by using call_in_appdomain Function. The second overload is application domain-safe; the newly created thread will always end up in the application domain of the caller of _beginthread or _beginthreadex.


Required header





For more compatibility information, see Compatibility.

Multithreaded versions of the C run-time libraries only.


The following example uses _beginthread and _endthread.

// crt_BEGTHRD.C
// processor: x86
#include <windows.h>
#include <process.h>    /* _beginthread, _endthread */
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>

void Bounce( void *ch );
void CheckKey( void *dummy );


HANDLE hStdOut;         /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi;    /* Console information structure */

int main()
    CHAR    ch = 'A';

    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

   GetConsoleScreenBufferInfo( hStdOut, &csbi );

    _beginthread( CheckKey, 0, NULL );

    /* Loop until CheckKey terminates program. */
    while( repeat )
        /* On first loops, launch character threads. */

        /* Wait one second between loops. */
        Sleep( 1000L );

void CheckKey( void *dummy )
    repeat = 0;    /* _endthread implied */


 * around on the screen.
 * Params: ch - the letter to be moved
void Bounce( void *ch )
    char    blankcell = 0x20;
    char    blockcell = (char) ch;
    BOOL    first = TRUE;
   COORD   oldcoord, newcoord;
   DWORD   result;

    srand( _threadid );
    newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
    newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
    while( repeat )
        /* Pause between loops. */
        Sleep( 100L );

        if( first )
            first = FALSE;

        oldcoord.X = newcoord.X;
        oldcoord.Y = newcoord.Y;
        newcoord.X += GetRandom( -1, 1 );
        newcoord.Y += GetRandom( -1, 1 );

        if( newcoord.X < 0 )
            newcoord.X = 1;
        else if( newcoord.X == csbi.dwSize.X )
            newcoord.X = csbi.dwSize.X - 2;
        else if( newcoord.Y < 0 )
            newcoord.Y = 1;
        else if( newcoord.Y == csbi.dwSize.Y )
            newcoord.Y = csbi.dwSize.Y - 2;

    /* _endthread given to terminate */

Press any key to end the sample application.

The following sample code demonstrates how you can use the thread handle that's returned by _beginthreadex with the synchronization API WaitForSingleObject. The main thread waits for the second thread to terminate before it continues. When the second thread calls _endthreadex, it causes its thread object to go to the signaled state. This allows the primary thread to continue running. This cannot be done with _beginthread and _endthread, because _endthread calls CloseHandle, which destroys the thread object before it can be set to the signaled state.

// crt_begthrdex.cpp
// compile with: /MT
#include <windows.h>
#include <stdio.h>
#include <process.h>

unsigned Counter; 
unsigned __stdcall SecondThreadFunc( void* pArguments )

    while ( Counter < 1000000 )

    _endthreadex( 0 );
    return 0;

int main()
    HANDLE hThread;
    unsigned threadID;


    // Create the second thread.

    // 1000000 yet.
    WaitForSingleObject( hThread, INFINITE );
    // Destroy the thread object.
    CloseHandle( hThread );
Creating second thread...
In second thread...
Counter should be 1000000; it is-> 1000000
Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
© 2014 Microsoft. All rights reserved.