_beginthread
, _beginthreadex
Crea un thread.
Sintassi
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
);
Parametri
start_address
Indirizzo iniziale di una routine che avvia l'esecuzione di un nuovo thread. Per _beginthread
, la convenzione di __cdecl
chiamata è (per il codice nativo) o __clrcall
(per il codice gestito). Per _beginthreadex
, la convenzione di __stdcall
chiamata è (per il codice nativo) o __clrcall
(per il codice gestito).
stack_size
Dimensione dello stack per un nuovo thread, oppure 0.
arglist
Elenco di argomenti da passare a un nuovo thread o NULL
.
Security
Puntatore a una SECURITY_ATTRIBUTES
struttura che determina se l'handle restituito può essere ereditato dai processi figlio. Se Security
è NULL
, l'handle non può essere ereditato.
initflag
Flag che controllano lo stato iniziale di un nuovo thread. Impostare initflag
su 0 per l'esecuzione immediata o per CREATE_SUSPENDED
creare il thread in uno stato sospeso. Usare ResumeThread
per eseguire il thread. Impostare initflag
su STACK_SIZE_PARAM_IS_A_RESERVATION
come contrassegno da usare stack_size
come dimensione di riserva iniziale dello stack in byte. Se questo flag non è specificato, stack_size
specifica le dimensioni del commit.
thrdaddr
Punta a una variabile a 32 bit che riceve l'identificatore del thread. Se è NULL
, non viene usato.
Valore restituito
Se completata correttamente, ognuna di queste funzioni restituisce un handle per il thread appena creato. Tuttavia, se il thread appena creato termina troppo rapidamente, _beginthread
potrebbe non restituire un handle valido. Vedere la discussione nella sezione Osservazioni. In caso di errore, _beginthread
restituisce -1L e errno
viene impostato su EAGAIN
se sono presenti troppi thread, su EINVAL
se l'argomento non è valido o le dimensioni dello stack non sono corrette oppure su EACCES
se sono presenti risorse insufficienti, ad esempio memoria. In caso di errore, _beginthreadex
restituisce 0 e vengono impostati errno
e _doserrno
.
Se start_address
è NULL
, viene richiamato il gestore di parametri non validi, come descritto in Convalida dei parametri. Se l'esecuzione può continuare, queste funzioni impostano errno
su EINVAL
e restituiscono -1.
Per altre informazioni su questi e altri codici restituiti, vedere errno
, _doserrno
, _sys_errlist
e _sys_nerr
.
Per altre informazioni su uintptr_t
, vedere Tipi standard.
Osservazioni:
La funzione _beginthread
crea un thread che inizia l'esecuzione di una routine presente in start_address
. La routine in start_address
deve usare la convenzione di chiamata __cdecl
(per il codice nativo) o __clrcall
(per il codice gestito) e non dovrebbe avere alcun valore restituito. Quando il thread viene restituito da tale routine, viene terminato automaticamente. Per altre informazioni sui thread, vedere Supporto multithreading per il codice precedente (Visual C++).
_beginthreadex
assomiglia più strettamente _beginthread
all'API Win32CreateThread
. _beginthreadex
differisce da _beginthread
nei seguenti modi:
_beginthreadex
ha altri tre parametri:initflag
,Security
ethreadaddr
. Il nuovo thread può essere creato in uno stato sospeso, con una sicurezza specificata ed è possibile accedervi usandothrdaddr
, che è l'identificatore del thread.La routine in
start_address
che viene passata a_beginthreadex
deve usare la convenzione di chiamata__stdcall
(per il codice nativo) o__clrcall
(per il codice gestito) e deve restituire un codice di uscita del thread._beginthreadex
restituisce 0 in caso di errore, anziché -1L.Un thread creato tramite
_beginthreadex
viene terminato da una chiamata a_endthreadex
.
La funzione _beginthreadex
offre maggiore controllo su come viene creato il thread rispetto a _beginthread
. La funzione _endthreadex
è inoltre più flessibile. Ad esempio, con _beginthreadex
, è possibile usare informazioni di sicurezza, impostare lo stato iniziale del thread (in esecuzione o in sospeso) e ottenere l'identificatore del thread appena creato. È anche possibile usare l'handle di thread restituito da _beginthreadex
con le API di sincronizzazione, che non è possibile eseguire con _beginthread
.
_beginthreadex
è più sicuro da usare rispetto _beginthread
a . Se il thread generato da _beginthread
termina rapidamente, l'handle restituito al chiamante di _beginthread
potrebbe essere non valido o puntare a un altro thread. Tuttavia, l'handle restituito da _beginthreadex
deve essere chiuso dal chiamante di _beginthreadex
, quindi è garantito che sia un handle valido se _beginthreadex
non ha restituito un errore.
È possibile chiamare o _endthreadex
in modo _endthread
esplicito per terminare un thread, _endthread
ma viene _endthreadex
chiamato automaticamente quando il thread viene restituito dalla routine passata come parametro. La terminazione di un thread con una chiamata a _endthread
o a _endthreadex
consente di assicurare il ripristino corretto delle risorse allocate per il thread.
_endthread
chiude automaticamente l'handle di thread, mentre _endthreadex
non lo è. Pertanto, quando si usa _beginthread
e _endthread
, non chiudere in modo esplicito l'handle di thread chiamando l'API Win32 CloseHandle
. Questo comportamento è diverso dall'API Win32 ExitThread
.
Nota
Per un file eseguibile collegato a Libcmt.lib, non chiamare l'API Win32 ExitThread
in modo da non impedire al sistema di runtime di recuperare le risorse allocate. _endthread
e _endthreadex
recuperano le risorse del thread allocate, quindi chiamano ExitThread
.
Il sistema operativo gestisce l'allocazione dello stack quando si chiama _beginthread
o _beginthreadex
. Non è necessario passare l'indirizzo dello stack di thread a una di queste funzioni. Inoltre, l'argomento stack_size
può essere 0, nel qual caso il sistema operativo usa lo stesso valore dello stack specificato per il thread principale.
arglist
è un parametro da passare al thread appena creato. In genere, si tratta dell'indirizzo di un elemento di dati, ad esempio una stringa di caratteri. arglist
può essere NULL
se non è necessario, ma _beginthread
deve _beginthreadex
essere assegnato un valore da passare al nuovo thread. Tutti i thread vengono terminati se un thread qualsiasi chiama abort
, exit
, _exit
o ExitProcess
.
Le impostazioni locali del nuovo thread vengono inizializzate usando le informazioni locali correnti globali per processo. Se le impostazioni locali per thread sono abilitate da una chiamata a _configthreadlocale
(solo a livello globale o solo per i nuovi thread), il thread può modificare le impostazioni locali indipendentemente da altri thread chiamando setlocale
o _wsetlocale
. I thread che non hanno il flag delle impostazioni locali per thread possono influire sulle informazioni sulle impostazioni locali in tutti gli altri thread che non hanno il flag delle impostazioni locali per thread e anche tutti i thread appena creati. Per altre informazioni, vedere Locale.
Per /clr
il codice _beginthread
e _beginthreadex
ognuno ha due overload. Uno accetta un puntatore a una funzione di convenzione di chiamata nativa e l'altro accetta un __clrcall
puntatore a funzione. Il primo overload non è sicuro per il dominio dell'applicazione e non sarà mai. Se si scrive /clr
codice, è necessario assicurarsi che il nuovo thread entri nel dominio applicazione corretto prima di accedere alle risorse gestite. A tale scopo, ad esempio, è possibile usare call_in_appdomain
. Il secondo overload è indipendente dal dominio applicazione. Il thread appena creato finirà sempre nel dominio applicazione del chiamante di _beginthread
o di _beginthreadex
.
Per impostazione predefinita, lo stato globale di questa funzione è limitato all'applicazione. Per modificare questo comportamento, vedere Stato globale in CRT.
Requisiti
Ciclo | Intestazione obbligatoria |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Per altre informazioni sulla compatibilità, vedere Compatibility (Compatibilità).
Librerie
Solo versioni multithread delle librerie di runtime C .
Per usare _beginthread
o _beginthreadex
, l'applicazione deve essere collegata a una delle librerie di runtime C con multithreading.
Esempi
Nell'esempio seguente vengono usate _beginthread
e _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();
}
Premere un tasto qualsiasi per chiudere l'applicazione di esempio.
Il codice di esempio seguente illustra come usare l'handle di thread restituito da _beginthreadex
con l'API WaitForSingleObject
di sincronizzazione . Il thread principale attende che il secondo thread termini prima di continuare. Quando il secondo thread chiama _endthreadex
, l'oggetto thread passa allo stato segnalato, che consente al thread primario di continuare l'esecuzione. Non può essere eseguita con _beginthread
e _endthread
, perché _endthread
chiama CloseHandle
, che elimina l'oggetto thread prima che possa essere impostato sullo stato segnalato.
// 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