_beginthread, _beginthreadex
Crea un thread.
Importante |
---|
Questa API non può essere utilizzata nelle applicazioni che vengono eseguite in Windows Runtime.Per ulteriori informazioni, vedere Funzioni CRT non supportate con /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
);
Parametri
start_address
Indirizzo iniziale di una routine che avvia l'esecuzione di un nuovo thread.Per _beginthread, la convenzione di chiamata è __cdecl (per il codice nativo) o __clrcall (per il codice gestito); per _beginthreadex, è __stdcall (per il codice nativo) o __clrcall (per il codice gestito).stack_size
Dimensione dello stack per un nuovo thread o 0.Arglist
Elenco di argomenti da passare a un nuovo thread o NULL.Security
Puntatore a una struttura SECURITY_ATTRIBUTES che determina se l'handle restituito può essere ereditato dai processi figlio.Se NULL, l'handle non può essere ereditato.Deve essere NULL per le applicazioni Windows 95.Initflag
Stato iniziale di un nuovo thread (0 per in esecuzione o CREATE_SUSPENDED per sospeso); utilizzare ResumeThread per eseguire il thread.Thrdaddr
Punta a una variabile a 32 bit che riceve l'identificatore del thread.Potrebbe essere NULL, nel qual caso non viene utilizzato.
Valore restituito
Se viene 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 Remarks )._beginthread restituisce -1L nel caso di errore, nel qual caso errno è impostato su EAGAIN se sono presenti troppi thread, su EINVAL se l'argomento non è valido o la dimensione dello stack è errata, o su EACCES nel caso di risorse insufficienti (ad esempio memoria)._beginthreadex restituisce 0 nel caso di errore, nel qual caso vengono impostati errno e _doserrno.
Se startaddress è NULL, viene richiamato il gestore di parametro non valido, come descritto in Convalida dei parametri.Se l'esecuzione può continuare, queste funzioni impostano errno a EINVAL e restituiscono -1.
Per ulteriori informazioni su questi e altri codici restituiti, vedere _doserrno, errno, _sys_errlist, e _sys_nerr.
Per ulteriori informazioni su uintptr_t, vedere Tipi standard.
Note
La funzione _beginthread crea un thread che inizia l'esecuzione di una routine che è presente in start_address.La routine in start_address deve utilizzare 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 quella routine, viene terminato automaticamente.Per ulteriori informazioni sui thread, vedere Multithreading.
_beginthreadex è analoga a CreateThread dell'API Win32 più di quanto lo sia _beginthread._beginthreadex differisce da _beginthread nei modi seguenti:
_beginthreadex dispone di tre parametri aggiuntivi: initflag, security, e threadaddr.Il nuovo thread può essere creato in uno stato sospeso, con una sicurezza specificata (solo Windows NT), ed è possibile accedervi utilizzando thrdaddr, che è l'identificatore del thread.
La routine in start_address che viene passata a _beginthreadex deve utilizzare 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 con _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 utilizzare informazioni di sicurezza, impostare lo stato iniziale del thread (in esecuzione o sospeso), e ottenere l'identificatore di thread del thread appena creato.È inoltre possibile utilizzare l'handle del thread restituito da _beginthreadex con le API di sincronizzazione. Questa operazione non può essere eseguita con _beginthread.
È preferibile utilizzare _beginthreadex rispetto a _beginthread.Se il thread generato da _beginthread termina rapidamente, l'handle restituito al chiamante di _beginthread potrebbe essere non valido o, peggio, puntare a un altro thread.Tuttavia, l'handle restituito da _beginthreadex deve essere chiuso dal chiamante di _beginthreadex, pertanto è sempre un handle valido se _beginthreadex non ha restituito un errore.
È possibile chiamare _endthread o _endthreadex in modo esplicito per terminare un thread; tuttavia, _endthread o _endthreadex vengono chiamati automaticamente quando il thread termina la 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 del thread (mentre _endthreadex non lo fa).Pertanto, quando si utilizzano _beginthread e _endthread, l'handle del thread non viene chiuso in modo esplicito chiamando CloseHandle dell'API Win32.Questo comportamento è diverso da ExitThread dell'API Win32.
[!NOTA]
Per un file eseguibile collegato a Libcmt.lib, non chiamare ExitThread dell'API Win32; in questo modo si impedisce al sistema in fase di esecuzione di recuperare le risorse allocate._endthread e _endthreadex recuperano le risorse allocate al thread e poi chiamano ExitThread.
Il sistema operativo gestisce l'allocazione dello stack quando vengono chiamate _beginthread o _beginthreadex; non è necessario passare l'indirizzo dello stack di thread a nessuna di queste funzioni.Inoltre, l'argomento stack_size può essere 0, nel qual caso il sistema operativo utilizza lo stesso valore dello stack specificato per il thread principale.
arglist è un parametro da passare al thread appena creato.In genere è l'indirizzo di un elemento di dati, quale una stringa di caratteri.arglist può essere NULL se non è necessario, ma _beginthread e _beginthreadex devono essere dotate di un valore da passare al nuovo thread.Tutti i thread vengono terminati se un thread chiama abort, exit, _exit, o ExitProcess.
Le impostazioni locali del nuovo thread vengono ereditate dal suo thread padre.Se le impostazioni locali del thread per sono abilitate da una chiamata a _configthreadlocale (solo o globalmente o per i nuovi thread), il thread può modificare le sue impostazioni locali indipendentemente dal proprio padre chiamando setlocale o _wsetlocale.Per ulteriori informazioni, vedere Impostazioni locali.
Per codice misto e puro, _beginthread e _beginthreadex dispongono di due overload, uno che accetta un puntatore alla funzione nativa della convenzione di chiamata, l'altro che accetta un puntatore alla funzione __clrcall.Il primo overload non è indipendente dal dominio applicazione e non lo sarà mai.Se si sta scrivendo codice misto o puro è necessario assicurarsi che il nuovo thread acceda al dominio dell'applicazione corretto prima di accedere alle risorse gestite.Questa operazione può essere eseguita, ad esempio, utilizzando Funzione call_in_appdomain.Il secondo overload è indipendente dal dominio applicazione; il thread appena creato finirà sempre nel dominio applicazione del chiamante di _beginthread o _beginthreadex.
Requisiti
Routine |
Intestazione obbligatoria |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Per ulteriori informazioni sulla compatibilità, vedere Compatibilità nell'introduzione.
Librerie
Solo versioni con multithreading delle Librerie di runtime C.
Per utilizzare _beginthread o _beginthreadex, l'applicazione deve essere collegata a una delle librerie di runtime C con multithreading.
Esempio
Nell'esempio seguente vengono utilizzate _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 *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();
}
premere un tasto per terminare
Nell'esempio di codice seguente viene illustrato come utilizzare l'handle del thread restituito da _beginthreadex con l'API di sincronizzazione WaitForSingleObject.Il thread principale attende che il secondo thread termini prima di continuare.Quando il secondo thread chiama _endthreadex, il relativo oggetto thread passerà allo stato segnalato.Ciò consentirà al thread primario di continuare l'esecuzione.Questa operazione non può essere eseguita con _beginthread e _endthread, poiché _endthread chiama CloseHandle, eliminando 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 );
}
Equivalente .NET Framework
System::Threading::Thread::Start