_beginthread
, _beginthreadex
Crée un thread.
Syntaxe
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
);
Paramètres
start_address
Adresse de début d'une routine qui commence l'exécution d'un nouveau thread. Pour _beginthread
, la convention d’appel est soit __cdecl
(pour le code natif) soit __clrcall
(pour le code managé). Pour _beginthreadex
, la convention d’appel est soit __stdcall
(pour le code natif) soit __clrcall
(pour le code managé).
stack_size
Taille de la pile d'un nouveau thread ou 0.
arglist
Liste d’arguments à passer à un nouveau thread, ou NULL
.
Security
Pointeur vers une SECURITY_ATTRIBUTES
structure qui détermine si le handle retourné peut être hérité par les processus enfants. Si Security
c’est NULL
le cas, le handle ne peut pas être hérité.
initflag
Indicateurs qui contrôlent l'état initial d'un nouveau thread. Définissez initflag
la valeur 0 pour s’exécuter immédiatement ou pour CREATE_SUSPENDED
créer le thread dans un état suspendu ; utilisez-le ResumeThread
pour exécuter le thread. Définissez l’indicateur initflag
à utiliser stack_size
comme taille de réserve initiale de la pile en octets ; si cet indicateur n’est pas spécifié, stack_size
spécifie la taille de validation.STACK_SIZE_PARAM_IS_A_RESERVATION
thrdaddr
Pointe vers une variable 32 bits qui reçoit l'identificateur du thread. Si c’est NULL
le cas, il n’est pas utilisé.
Valeur retournée
En cas de réussite, chacune de ces fonctions retourne un handle au nouveau thread. Toutefois, si le nouveau thread se ferme trop rapidement, _beginthread
peut ne pas retourner un handle valide. (Consultez la discussion dans la section Remarques.) Sur une erreur, _beginthread
retourne -1L et errno
est défini EAGAIN
sur s’il y a trop de threads, si EINVAL
l’argument n’est pas valide ou si la taille de la pile est incorrecte, ou si EACCES
des ressources insuffisantes (telles que la mémoire) sont insuffisantes. En cas d'erreur, _beginthreadex
retourne 0 et errno
et _doserrno
sont définis.
Si start_address
a la valeur NULL
, le gestionnaire de paramètre non valide est appelé, comme décrit dans Validation de paramètre. Si l'exécution est autorisée à se poursuivre, ces fonctions définissent errno
avec la valeur EINVAL
et retournent -1.
Pour plus d’informations sur ces codes de retour et d’autres codes de retour, consultez , , _sys_errlist
_doserrno
et _sys_nerr
.errno
Pour plus d’informations sur uintptr_t
, consultez types Standard.
Notes
La fonction _beginthread
crée un thread qui commence l'exécution d'une routine à start_address
. La routine à start_address
doit utiliser la convention d'appel __cdecl
(pour le code natif) ou __clrcall
(pour le code managé) et ne doit pas avoir de valeur de retour. Lorsque le thread revient de cette routine, il est arrêté automatiquement. Pour plus d’informations sur les threads, consultez la prise en charge du multithreading pour le code plus ancien (Visual C++).
_beginthreadex
ressemble à l’API Win32 CreateThread
plus étroitement que cela _beginthread
. _beginthreadex
diffère de _beginthread
des manières suivantes :
_beginthreadex
a trois paramètres supplémentaires :initflag
,Security
etthreadaddr
. Le nouveau thread peut être créé dans un état suspendu, avec une sécurité spécifiée, et il est accessible à l'aide dethrdaddr
, qui représente l'identificateur du thread.La routine à
start_address
passée à_beginthreadex
doit utiliser la convention d'appel__stdcall
(pour le code natif) ou__clrcall
(pour le code managé) et doit retourner un code de sortie de thread._beginthreadex
retourne 0 en cas d'échec plutôt que -1L.Un thread créé à l’aide
_beginthreadex
est arrêté par un appel à_endthreadex
.
La fonction _beginthreadex
vous permet de mieux contrôler la création du thread que _beginthread
. La fonction _endthreadex
est également plus flexible. Par exemple, avec _beginthreadex
, vous pouvez utiliser les informations de sécurité, définir l'état initial du thread (en cours d'exécution ou suspendu) et obtenir l'identificateur du thread nouvellement créé. Vous pouvez également utiliser le handle de thread retourné par _beginthreadex
les API de synchronisation, que vous ne pouvez pas faire avec _beginthread
.
_beginthreadex
est plus sûr d’utiliser que _beginthread
. Si le thread généré par _beginthread
se ferme rapidement, le handle retourné à l'appelant de _beginthread
peut être non valide ou pointer sur un autre thread. Toutefois, le handle retourné par _beginthreadex
doit être fermé par l’appelant, _beginthreadex
de sorte qu’il est garanti qu’il soit un handle valide s’il _beginthreadex
n’a pas retourné d’erreur.
Vous pouvez appeler _endthread
ou _endthreadex
mettre fin explicitement à un thread ; toutefois, _endthread
ou _endthreadex
est appelé automatiquement lorsque le thread retourne à partir de la routine passée en tant que paramètre. La fin d'un thread par un appel à _endthread
ou _endthreadex
permet de garantir une récupération correcte des ressources allouées pour le thread.
_endthread
ferme automatiquement le handle de thread, alors que ce n’est pas le cas _endthreadex
. Par conséquent, lorsque vous utilisez _beginthread
et _endthread
que vous ne fermez pas explicitement le handle de thread en appelant l’API Win32 CloseHandle
. Ce comportement diffère de l’API Win32 ExitThread
.
Remarque
Pour un fichier exécutable lié à Libcmt.lib, n'appelez pas l'API Win32 ExitThread
afin de ne pas empêcher le système runtime de récupérer les ressources allouées. _endthread
et _endthreadex
récupèrent les ressources de thread allouées, puis appellent ExitThread
.
Le système d'exploitation gère l'allocation de la pile lorsque _beginthread
ou _beginthreadex
est appelé ; vous n'êtes pas obligé de passer l'adresse de la pile des threads à l'une ou l'autre de ces fonctions. En outre, l'argument stack_size
peut être 0, auquel cas le système d'exploitation utilise la même valeur que la pile spécifiée pour le thread principal.
arglist
est un paramètre à passer au thread nouvellement créé. En règle générale, il s’agit de l’adresse d’un élément de données, telle qu’une chaîne de caractères. arglist
peut être NULL
s’il n’est pas nécessaire, mais _beginthread
doit _beginthreadex
avoir une valeur à passer au nouveau thread. Tous les threads sont arrêtés si un thread appelle abort
, exit
, _exit
, ou ExitProcess
.
Les paramètres régionaux du nouveau thread sont initialisés à l’aide des informations locales globales par processus. Si les paramètres régionaux par thread sont activés par un appel à _configthreadlocale
(globalement ou pour les nouveaux threads uniquement), le thread peut modifier ses paramètres régionaux indépendamment des autres threads en appelant setlocale
ou _wsetlocale
. Les threads qui n’ont pas l’indicateur de paramètres régionaux par thread peuvent affecter les informations de paramètres régionaux dans tous les autres threads qui n’ont pas non plus l’indicateur de paramètres régionaux par thread, ainsi que tous les threads nouvellement créés. Pour plus d’informations, consultez Locale.
Pour /clr
le code, _beginthread
et _beginthreadex
chacun a deux surcharges. L’un prend un pointeur de fonction de convention d’appel natif, et l’autre prend un pointeur de __clrcall
fonction. La première surcharge n’est pas sécurisée par le domaine d’application et ne sera jamais. Si vous écrivez /clr
du code, vous devez vous assurer que le nouveau thread entre dans le domaine d’application approprié avant d’accéder aux ressources managées. Vous pouvez le faire, par exemple, à l’aide call_in_appdomain
de . La seconde surcharge est sécurisée au niveau du domaine d'application ; le nouveau thread finit toujours dans le domaine d'application de l'appelant de _beginthread
ou _beginthreadex
.
Par défaut, l’état global de cette fonction est limité à l’application. Pour modifier ce comportement, consultez État global dans le CRT.
Spécifications
Routine | En-tête requis |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Pour plus d’informations sur la compatibilité, consultez Compatibility.
Bibliothèques
Uniquement les versions multithread des bibliothèques Runtime C .
Pour utiliser _beginthread
ou _beginthreadex
, l'application doit être liée à l'une des bibliothèques multithread Runtime C.
Exemples
L'exemple suivant utilise _beginthread
et _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.
else
continue;
Beep((ci.Char.AsciiChar - 'A') * 100, 175);
}
// _endthread given to terminate
_endthread();
}
Appuyez sur n'importe quelle touche pour fermer l'exemple d'application.
L’exemple de code suivant montre comment utiliser le handle de thread retourné par _beginthreadex
l’API WaitForSingleObject
de synchronisation. Le thread principal attend que le second thread se termine avant de continuer. Lorsque le deuxième thread appelle _endthreadex
, son objet thread passe à l’état signalé, ce qui permet au thread principal de continuer à s’exécuter. Il ne peut pas être effectué avec _beginthread
et _endthread
, car _endthread
les appels CloseHandle
, qui détruit l’objet thread avant de pouvoir être défini sur l’état signalé.
// 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