_beginthread
, _beginthreadex
Cria um thread.
Sintaxe
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
);
Parâmetros
start_address
Endereço inicial de uma rotina que inicia a execução de um novo thread. Para _beginthread
, a convenção de chamada é __cdecl
(para código nativo) ou __clrcall
(para código gerenciado). Para _beginthreadex
, a convenção de chamada é __stdcall
(para código nativo) ou __clrcall
(para código gerenciado).
stack_size
Tamanho da pila para um novo thread ou 0.
arglist
Lista de argumentos a ser apresentada a um novo thread ou NULL
.
Security
O ponteiro para uma estrutura SECURITY_ATTRIBUTES
que determina se o identificador retornado pode ser herdado por processos filhos. Se Security
for NULL
, o identificador não poderá ser herdado.
initflag
Sinalizadores que controlam o estado inicial de um novo thread. Defina initflag
como 0 para executar imediatamente ou como CREATE_SUSPENDED
para criar o thread em um estado suspenso. Use ResumeThread
para executar o thread. Defina initflag
como STACK_SIZE_PARAM_IS_A_RESERVATION
sinalizador para usar stack_size
como o tamanho de reserva inicial da pilha em bytes; se esse sinalizador não for especificado, stack_size
especifica o tamanho da confirmação.
thrdaddr
Aponta para uma variável de 32 bits que recebe o identificador de thread. Se for NULL
, não será usado.
Valor retornado
Em caso de êxito, cada uma dessas funções retorna um indicador para o thread novo. No entanto, se esse novo thread surgir muito rápido, _beginthread
pode não retornar um indicador válido. (Confira a discussão na seção Comentários.) Em caso de erro, _beginthread
retornará -1L e errno
será definido como EAGAIN
se houver muitos threads, como EINVAL
se o argumento for inválido ou o tamanho da pilha estiver incorreto, ou como EACCES
se não houver recursos suficientes (como memória). Em caso de erro, _beginthreadex
retorna 0 e errno
e _doserrno
são definidos.
Se start_address
for NULL
, o manipulador de parâmetro inválido será chamado, conforme descrito em Validação de parâmetro. Se a execução puder continuar, essas funções definirão errno
como EINVAL
e retornarão -1.
Para obter mais informações sobre esses e outros códigos de retorno, confira errno
, _doserrno
, _sys_errlist
e _sys_nerr
.
Para obter mais informações sobre uintptr_t
o , consulte Tipos padrão.
Comentários
A função _beginthread
cria um thread que inicia a execução de uma rotina em start_address
. A rotina em start_address
deve usar a convenção de chamadas __cdecl
(para código nativo) ou __clrcall
(para código gerenciado) e não apresentar valor retornado. Quando o thread retorna dessa rotina, ele é encerrado automaticamente. Para obter mais informações sobre threads, consulte Suporte a multithreading para código mais antigo (Visual C++).
_beginthreadex
tem mais semelhanças do que _beginthread
com a API CreateThread
do Win32. _beginthreadex
é diferente de _beginthread
nestes aspectos:
_beginthreadex
tem mais três parâmetros:initflag
,Security
, ethreadaddr
. O novo thread pode ser criado em estado suspenso, com a segurança especificada, e pode ser acessado com uso dethrdaddr
, que é o identificador do thread.A rotina em
start_address
, que é informada a_beginthreadex
, deve usar a convenção de chamadas__stdcall
(para código nativo) ou__clrcall
(para código gerenciado) e retornar um código de saída do thread._beginthreadex
retorna 0 em caso de falha, em vez de -1L.Um thread que é criado usando
_beginthreadex
é terminado por uma chamada para_endthreadex
.
A função _beginthreadex
proporciona mais controle do que a _beginthread
sobre o método de criação do thread. A função _endthreadex
também é mais flexível. Por exemplo, com a função _beginthreadex
, você pode usar informações de segurança, definir o estado iniciado do thread (em execução ou suspenso) e obter o identificador do thread recém-criado. Você também pode usar o identificador de thread retornado por _beginthreadex
com as APIs de sincronização, o que não pode ser feito com _beginthread
o .
_beginthreadex
é mais seguro de usar do que _beginthread
. Se o thread gerado por _beginthread
surgir rapidamente, o indicador retornado para o chamador de _beginthread
pode ser inválido ou apontar para outro thread. No entanto, o identificador retornado por _beginthreadex
deve ser fechado pelo chamador de _beginthreadex
, portanto, é garantido que seja um identificador válido se _beginthreadex
não retornar um erro.
Você pode chamar a função _endthread
ou _endthreadex
explicitamente para terminar um thread. No entanto, a função _endthread
ou _endthreadex
é chamada automaticamente quando o thread volta da rotina passada como parâmetro. Chamar a função _endthread
ou _endthreadex
para terminar um thread ajuda a garantir que os recursos alocados ao thread sejam devidamente recuperados.
_endthread
fecha automaticamente a alça de rosca, enquanto _endthreadex
não. Portanto, quando você usar _beginthread
e _endthread
, não feche explicitamente o identificador de thread chamando a API do Win32 CloseHandle
. Esse comportamento é diferente daquele da API ExitThread
do Win32.
Observação
No caso de arquivos executáveis vinculados a Libcmt.lib, não chame a API ExitThread
do Win32. Isso impede que o sistema do tempo de execução recupere os recursos alocados. As funções _endthread
e _endthreadex
recuperam os recursos alocados ao thread e chamam a API ExitThread
.
O sistema operacional trata a alocação da pilha quando _beginthread
ou _beginthreadex
é chamado. Você não precisa informar o endereço da pilha de threads para uma dessas funções. Além disso, o argumento stack_size
pode ser 0. Nesse caso, o sistema operacional usa o mesmo valor da pilha especificada para o thread principal.
arglist
é um parâmetro a ser informado no thread recém-criado. Normalmente, é o endereço de um item de dados, como uma cadeia de caracteres. arglist
pode ser NULL
se não for necessário, mas _beginthread
_beginthreadex
e deve receber algum valor para passar para o novo thread. Todos os threads são terminados se o thread chamar abort
, exit
, _exit
ou ExitProcess
.
A localidade do novo thread é inicializada usando as informações de localidade global atual por processo. Se a localidade por thread for habilitada por uma chamada para _configthreadlocale
(globalmente ou somente para novos threads), o thread poderá alterar a própria localidade independentemente de outros threads, chamando setlocale
ou _wsetlocale
. Os threads que não têm o sinalizador de localidade por thread definido podem afetar as informações de localidade em todos os outros threads que também não têm o sinalizador de localidade por thread definido e também em todos os threads recém-criados. Para obter mais informações, consulte Localidade.
Para código /clr
, cada um de _beginthread
e _beginthreadex
tem duas sobrecargas. Uma delas usa um ponteiro de funções de convenção de chamadas nativo, e a outra usa um ponteiro da função __clrcall
. A primeira sobrecarga não é segura para o domínio do aplicativo e nunca será. Se você estiver escrevendo /clr
código, deverá garantir que o novo thread entre no domínio correto do aplicativo antes de acessar os recursos gerenciados. Você pode fazer isso, por exemplo, usando call_in_appdomain
. A segunda sobrecarga é à prova de domínio do aplicativo. O novo thread sempre terminará no domínio do aplicativo do chamador de _beginthread
ou _beginthreadex
.
Por padrão, o estado global dessa função tem como escopo o aplicativo. Para alterar esse comportamento, confira Estado global no CRT.
Requisitos
Rotina | Cabeçalho necessário |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Para obter informações sobre compatibilidade, consulte Compatibilidade.
Bibliotecas
Somente versões multi-threaded da biblioteca em tempo de execução do C.
Para usar _beginthread
ou _beginthreadex
, o aplicativo deve vincular-se a uma das bibliotecas de tempo de execução C multithreaded.
Exemplos
Os exemplos a seguir usam _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();
}
Pressione qualquer tecla para encerrar um aplicativo de exemplo.
O código de exemplo a seguir demonstra como você pode usar o identificador de thread retornado por _beginthreadex
, com a API de sincronização WaitForSingleObject
. O thread principal aguarda o segundo thread encerrar antes de continuar. Quando o segundo thread chama _endthreadex
, ele faz com que seu objeto thread vá para o estado sinalizado, o que permite que o thread primário continue em execução. Isso não pode ser feito com _beginthread
e _endthread
, porque _endthread
chama CloseHandle
, que destrói o objeto thread antes que ele possa ser definido para o estado sinalizado.
// 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