使用 _beginthreadex
创建的线程已通过对 _endthreadex
的调用终止。
与 _beginthreadex
相比, _beginthread
让你可以在更大程度上控制如何创建线程。 _endthreadex
函数也更为灵活。 例如,通过 _beginthreadex
,你可以使用安全信息、设置线程的初始状态(运行或挂起)并获取新创建线程的线程标识符。 还可以将 返回 _beginthreadex
的线程句柄与同步 API 一起使用,而你无法使用 _beginthread
。
_beginthreadex
比 _beginthread
使用更安全。 如果由 _beginthread
生成的线程很快退出,则返回到 _beginthread
调用方的句柄可能无效或指向另一个线程。 但是,由 _beginthreadex
返回的句柄必须由 的 _beginthreadex
调用方关闭,因此,如果未 _beginthreadex
返回错误,则保证该句柄是有效的句柄。
可以显式调用 _endthread
或 _endthreadex
终止线程;但是,当线程从作为参数传递的例程中返回时,会自动调用 _endthread
或 _endthreadex
。 通过对 _endthread
或 _endthreadex
的调用来终止线程有助于确保正确恢复为线程分配的资源。
_endthread
自动关闭线程句柄,而 _endthreadex
不会。 因此,使用 _beginthread
和 _endthread
时,不要通过调用 Win32 CloseHandle
API 显式关闭线程句柄。 该行为与 Win32 ExitThread
API 不同。
对于与 Libcmt.lib 链接的可执行文件,请不要调用 Win32 ExitThread
API,这样就不会阻止运行时系统回收已分配的资源。 _endthread
和 _endthreadex
回收分配的线程资源,然后调用 ExitThread
。
当调用了 _beginthread
或 _beginthreadex
中的任一个时,操作系统将处理堆栈的分配;你不必将该线程堆栈的地址传递给这两个函数中的任何一个。 此外, stack_size
参数还可为 0,在这种情况下,操作系统使用的值与为主线程指定的堆栈相同。
arglist
是传递到新创建的线程的参数。 通常,它是数据项(如字符串)的地址。 arglist
NULL
如果不需要,可以为 ,但_beginthread
必须为 和 _beginthreadex
提供一些值才能传递给新线程。 如果任何线程调用 abort
、 exit
、 _exit
或 ExitProcess
,所有线程都会终止。
新线程的区域设置通过使用每进程全局当前区域设置信息来初始化。 如果通过对 _configthreadlocale
的调用(全局或仅针对新线程)启用了每线程区域设置,则线程可以通过调用 setlocale
或 _wsetlocale
独立从其他线程更改区域设置。 未设置每线程区域设置标志的线程可能会影响所有其他未设置每线程区域设置标志的线程以及所有新创建的线程中的区域设置信息。 有关详细信息,请参阅 Locale。
对于 /clr
代码,_beginthread
和 _beginthreadex
都有两个重载。 一个采用本机调用约定函数指针,另一个采用 __clrcall
函数指针。 第一个重载不是应用程序域安全的,并且永远不会是。 如果要编写 /clr
代码,必须确保新线程在访问托管资源之前进入正确的应用程序域。 例如, call_in_appdomain
可以使用 执行此操作。 第二个重载是应用程序安全域;新创建的线程总是在 _beginthread
或 _beginthreadex
调用方的应用程序域中结束。
默认情况下,此函数的全局状态范围限定为应用程序。 若要更改此行为,请参阅 CRT 中的全局状态。
例程所返回的值
必需的标头
若要使用 _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 * );
void CheckKey( void * );
// GetRandom returns a random integer between min and max.
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))
// GetGlyph returns a printable ASCII character value
#define GetGlyph( val ) ((char)((val + 32) % 93 + 33))
BOOL repeat = TRUE; // Global repeat flag
HANDLE hStdOut; // Handle for console window
CONSOLE_SCREEN_BUFFER_INFO csbi; // Console information structure
int main()
int param = 0;
int * pparam = ¶m;
// Get display screen's text row and column information.
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo( hStdOut, &csbi );
// Launch CheckKey thread to check for terminating keystroke.
_beginthread( CheckKey, 0, NULL );
// Loop until CheckKey terminates program or 1000 threads created.
while( repeat && param < 1000 )
// launch another character thread.
_beginthread( Bounce, 0, (void *) pparam );
// increment the thread parameter
param++;
// Wait one second between loops.
Sleep( 1000L );
// CheckKey - Thread to wait for a keystroke, then clear repeat flag.
void CheckKey( void * ignored )
_getch();
repeat = 0; // _endthread implied
// Bounce - Thread to create and control a colored letter that moves
// around on the screen.
// Params: parg - the value to create the character from
void Bounce( void * parg )
char blankcell = 0x20;
CHAR_INFO ci;
COORD oldcoord, cellsize, origin;
DWORD result;
SMALL_RECT region;
cellsize.X = cellsize.Y = 1;
origin.X = origin.Y = 0;
// Generate location, letter and color attribute from thread argument.
srand( _threadid );
oldcoord.X = region.Left = region.Right =
GetRandom(csbi.srWindow.Left, csbi.srWindow.Right - 1);
oldcoord.Y = region.Top = region.Bottom =
GetRandom(csbi.srWindow.Top, csbi.srWindow.Bottom - 1);
ci.Char.AsciiChar = GetGlyph(*((int *)parg));
ci.Attributes = GetRandom(1, 15);
while (repeat)
// Pause between loops.
Sleep( 100L );
// Blank out our old position on the screen, and draw new letter.
WriteConsoleOutputCharacterA(hStdOut, &blankcell, 1, oldcoord, &result);
WriteConsoleOutputA(hStdOut, &ci, cellsize, origin, ®ion);
// Increment the coordinate for next placement of the block.
oldcoord.X = region.Left;
oldcoord.Y = region.Top;
region.Left = region.Right += GetRandom(-1, 1);
region.Top = region.Bottom += GetRandom(-1, 1);
// Correct placement (and beep) if about to go off the screen.
if (region.Left < csbi.srWindow.Left)
region.Left = region.Right = csbi.srWindow.Left + 1;
else if (region.Right >= csbi.srWindow.Right)
region.Left = region.Right = csbi.srWindow.Right - 2;
else if (region.Top < csbi.srWindow.Top)
region.Top = region.Bottom = csbi.srWindow.Top + 1;
else if (region.Bottom >= csbi.srWindow.Bottom)
region.Top = region.Bottom = csbi.srWindow.Bottom - 2;
// If not at a screen border, continue, otherwise beep.
continue;
Beep((ci.Char.AsciiChar - '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 );
Creating second thread...
In second thread...
Counter should be 1000000; it is-> 1000000
进程和环境控制
_endthread
, _endthreadex
abort
exit
, _Exit
, _exit
GetExitCodeThread