_beginthread, _beginthreadex

创建线程。

重要

此 API 不能在运行时的窗口执行的应用程序。有关更多信息,请参见 CRT 函数不支持与 /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
    开始执行新线程实例的起始地址。 对于 _beginthread,调用约定是 __cdecl (对于本机代码) 或 __clrcall (对于托管代码);对于 _beginthreadex,它是 __stdcall (对于本机代码) 或 __clrcall (对于托管代码)。

  • stack_size
    新线程或 0 的堆栈大小。

  • Arglist
    参数列表传递到新线程或 NULL。

  • Security
    为确定的 SECURITY_ATTRIBUTES 结构的指针返回的句柄是否可由子进程继承。 如果为 null,句柄不能被继承。 必须为空对于 Windows 95 应用程序。

  • Initflag
    新的挂起的线程 (运行的0 或 CREATE_SUSPENDED ) 的初始状态;使用 ResumeThread 执行线程。

  • Thrdaddr
    指向接收线程标识符的 32 位变量。 在不使用情况下,可能是 NULL它。

返回值

如果成功,这些函数都返回一个处理到新创建的线程;但是,因此,如果新创建的线程太快速退出,_beginthread 可能不返回有效句柄 (参见中 Remarks 部分的讨论)。 _beginthread 返回在错误的 -1L,在 errno 设置为 EAGAIN,如果具有多个线程情况下,对 EINVAL,如果无效的参数或堆栈大小不正确,或者为 EACCES 后足够的资源 (如内存)。 在 errno 和 _doserrno 设置情况下,_beginthreadex 返回 0 在错误。

如果 startaddress 是 NULL,无效参数调用处理程序,如 参数验证所述。 如果执行允许继续,对 EINVAL 的这些功能集 errno 并且返回 -1。

有关这些属性和其他的更多信息返回代码示例,请参见 _doserrno、errno、_sys_errlist 和_sys_nerr

有关 uintptr_t的更多信息,请参见 标准类型

备注

_beginthread 函数开始创建实例的执行在 start_address的线程。 在 start_address 的实例必须使用 (对于托管代码) 调用约定 __cdecl (对于本机代码) 或 __clrcall,应没有返回值。 当线程从该实例时返回,它会自动停止。 有关线程的更多信息,请参见 多线程处理

_beginthreadex 比 _beginthread 非常类似于 Win32 CreateThread API。 _beginthreadex 与 _beginthread 以下方面有所不同:

  • _beginthreadex 有三个参数:initflag、security和 threadaddr。 新线程处于挂起状态后,以指定安全 (仅限 Windows NT) 使用 thrdaddr,因此,可访问,是线程标识符。

  • 在 start_address 的实例传递给 _beginthreadex 必须使用 (对于托管代码) 调用约定 __stdcall (对于本机代码) 或 __clrcall,并且必须返回线程退出代码。

  • _beginthreadex 返回 0 在失败,而不是 -1L。

  • 在 _beginthreadex 创建的线程通过对 _endthreadex的调用停止。

_beginthreadex 功能提供了对线程更好地控制如何与 _beginthread 创建。 _endthreadex 功能也更为灵活。 例如,与 _beginthreadex,可以使用安全信息,设置线程的初始状态 (运行或挂起的) 并获取新创建的线程的线程标识符。 您还可以使用与同步 API 的 _beginthreadex 返回的线程句柄,您无法执行与 _beginthread。

使用 _beginthreadex 比 _beginthread是安全。 如果 _beginthread 生成的线程快速退出,处理返回到 _beginthread 的调用方无效或,更糟糕,指向另一个线程。 但是,_beginthreadex 返回的句柄必须由 _beginthreadex的调用方关闭,因此,一定有效句柄,如果 _beginthreadex 未返回错误。

可以显式调用 _endthread_endthreadex 终止线程;但是,那么,当线程从作为参数时,通过的实例返回 _endthread 或_endthreadex 自动调用。 停止点与调用的线程传递 endthread 或 _endthreadex 帮助确保为线程分配的资源适当的恢复。

_endthread 自动关闭线程句柄 (而不 _endthreadex )。 因此,那么,当使用 _beginthread 和 _endthread时,不要通过调用 Win32 API CloseHandle 显式关闭线程句柄。 此行为与 Win32 API ExitThread 不同。

备注

对于使用 Libcmt.lib 链接的可执行文件,不要调用 Win32 API; ExitThread 这样可防止该运行时系统恢复已分配的资源。_endthread 和分发 _endthreadex 回收线程资源然后调用 ExitThread。

操作系统句柄堆栈的分配,当 _beginthread 或 _beginthreadex 调用;您不需要传入线程堆栈的地址到其中一种功能。 此外,在中,在为主线程情况下,使用值和堆栈所指定的操作系统 stack_size 参数可以为 0。

arglist 是传递的参数传递给新创建的线程。 它通常是 dataitem 的地址,例如字符字符串。 arglist 可以是 NULL,如果它不是必需的,但是,必须提供 _beginthread 和 _beginthreadex 某个值传递给新线程。 如果任何线程调用 abort、exit、_exit或 ExitProcess,所有线程终止。

新线程区域设置从其父线程继承。 每个线程区域设置通过对 _configthreadlocale 的调用活动 (或全局或仅适用于新线程),线程可以从其父独立地更改其区域设置通过调用 setlocale 或 _wsetlocale。 有关更多信息,请参见 区域设置

对于混合和纯代码,_beginthread 和 _beginthreadex 两个具有两个超负载,采用本机调用约定函数指针时,采用 __clrcall 函数指针的其他。 第一个超加载不是域安全的应用程序且从不一致。 如果您编写组合或纯代码必须确保新线程进入正确的应用程序域,则访问托管资源。 使用 call_in_appdomain 函数,可以执行此操作,例如。 第二个超负载是域安全的应用程序;新创建的线程在 _beginthread 或 _beginthreadex的调用方的应用程序域将始终结果。

要求

实例

必需的标头

_beginthread

<process.h>

_beginthreadex

<process.h>

有关更多兼容性信息,请参见中介绍的 兼容性

C 运行库 的多线程版本。

若要使用 _beginthread 或 _beginthreadex,应用程序必须与之一的多线程 C 运行库链接。

示例

下面的示例使用 _beginthread 和 _endthread。

// crt_BEGTHRD.C
// compile with: /MT /D "_X86_" /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 );

/* GetRandom returns a random integer between min and max. */
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

BOOL repeat = TRUE;     /* Global repeat flag and video variable */
HANDLE hStdOut;         /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi;    /* Console information structure */

int main()
{
    CHAR    ch = 'A';

    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

    /* Get display screen's text row and column information. */
   GetConsoleScreenBufferInfo( hStdOut, &csbi );

    /* Launch CheckKey thread to check for terminating keystroke. */
    _beginthread( CheckKey, 0, NULL );

    /* Loop until CheckKey terminates program. */
    while( repeat )
    {
        /* On first loops, launch character threads. */
        _beginthread( Bounce, 0, (void *) (ch++)  );

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

/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
void CheckKey( void *dummy )
{
    _getch();
    repeat = 0;    /* _endthread implied */

}

/* Bounce - Thread to create and and control a colored letter that moves
 * around on the screen.
 * Params: ch - the letter to be moved
 */
void Bounce( void *ch )
{
    /* Generate letter and color attribute from thread argument. */
    char    blankcell = 0x20;
    char    blockcell = (char) ch;
    BOOL    first = TRUE;
   COORD   oldcoord, newcoord;
   DWORD   result;


    /* Seed random number generator and get initial location. */
    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 );

        /* Blank out our old position on the screen, and draw new letter. */
        if( first )
            first = FALSE;
        else
         WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );
         WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );

        /* Increment the coordinate for next placement of the block. */
        oldcoord.X = newcoord.X;
        oldcoord.Y = newcoord.Y;
        newcoord.X += GetRandom( -1, 1 );
        newcoord.Y += GetRandom( -1, 1 );

        /* Correct placement (and beep) if about to go off the screen. */
        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;

        /* If not at a screen border, continue, otherwise beep. */
        else
            continue;
        Beep( ((char) ch - 'A') * 100, 175 );
    }
    /* _endthread given to terminate */
    _endthread();
}
  按任意键关闭

下面的代码示例演示如何使用与同步 API WaitForSingleObject的 _beginthreadex 返回的线程句柄。 会在继续之前,主线程等待第二个线程终止。 在第二个线程调用 _endthreadex时,它使其线程对象进入终止状态。 这使主线程继续运行。 这是不能对 _beginthread 和 _endthread,因为 _endthread 调用 CloseHandle,销毁线程对象,则可以将设置为终止状态之前。

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

unsigned Counter; 
unsigned __stdcall SecondThreadFunc( void* pArguments )
{
    printf( "In second thread...\n" );

    while ( Counter < 1000000 )
        Counter++;

    _endthreadex( 0 );
    return 0;
} 

int main()
{ 
    HANDLE hThread;
    unsigned threadID;

    printf( "Creating second thread...\n" );

    // Create the second thread.
    hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );

    // Wait until second thread terminates. If you comment out the line
    // below, Counter will not be correct because the thread has not
    // terminated, and Counter most likely has not been incremented to
    // 1000000 yet.
    WaitForSingleObject( hThread, INFINITE );
    printf( "Counter should be 1000000; it is-> %d\n", Counter );
    // Destroy the thread object.
    CloseHandle( hThread );
}
       

.NET Framework 等效项

System::Threading::Thread::Start

请参见

参考

处理和环境控件

_endthread, _endthreadex

abort

exit, _exit

GetExitCodeThread