_beginthread, beginthreadex
Cria um segmento.
Importante |
---|
Este API não pode ser usado em aplicativos executados em Tempo de Execução do Windows.Para obter mais informações, consulte Funções de CRT não suportadas com /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 );
Parâmetros
start_address
Endereço de início de uma rotina que iniciar a execução de um novo segmento.Para _beginthread, a convenção de chamada é cdecl (para código nativo) ou ( __clrcall para código gerenciado); para _beginthreadex, é __stdcall (para código nativo) ou ( __clrcall para código gerenciado).stack_size
Empilhar o tamanho de um novo segmento ou 0.Arglist
Lista de argumento a ser passada para um novo thread. ou NULLSecurity
Ponteiro a estrutura de SECURITY_ATTRIBUTES que determina se a alça retornado pode ser herdada pelos processos filho.Se NULL, o identificador não pode ser herdada.Deve ser NULO para aplicativos Windows 95.Initflag
Estado inicial de um novo segmento (0 para executar ou de CREATE_SUSPENDED para suspenso); use ResumeThread para executar o segmento.Thrdaddr
Aponta para uma variável de 32 bits que recebe o identificador de segmento.Pode ser NULL, nesse caso não é usado.
Valor de retorno
Se com êxito, cada uma dessas funções retorna um identificador para o segmento recém-criado; no entanto, se o segmento recém-criado sai muito rapidamente, _beginthread não pode retornar um identificador válido (consulte discussões na seção de Remarks )._beginthread retorna -1L em um erro, nesse caso errno é definido como EAGAIN se há muitos segmentos, a EINVAL se o argumento é inválido ou o tamanho da pilha está incorreto, ou a EACCES no caso de insuficientes recursos (como a memória)._beginthreadex retorna 0 em um erro, nesse caso errno e _doserrno são definidos.
Se startaddress é NULL, o manipulador inválido do parâmetro é invocado, como descrito em Validação de parâmetro.Se a execução é permitida continuar, este errno definir funções a EINVAL e retorne -1.
Para obter mais informações sobre esses e outros códigos de retorno, consulte _doserrno, errno, _sys_errlist, e _sys_nerr.
Para obter mais informações sobre uintptr_t, consulte Tipos padrão.
Comentários
A função de _beginthread cria um segmento que iniciar a execução de uma rotina em start_address.A rotina em start_address deve usar __cdecl (para código nativo) ou ( __clrcall para código gerenciado) que chama a convenção e não deve ter nenhum valor de retorno.Quando retorna o segmento da rotina, é encerrado automaticamente.Para obter mais informações sobre os segmentos, consulte Multithreading.
_beginthreadex é semelhante à API Win32 CreateThread melhor do que faz _beginthread ._beginthreadex difere de _beginthread das seguintes maneiras:
_beginthreadex tem três parâmetros adicionais: initflag, security, e threadaddr.O novo thread pode ser criado em um estado suspenso, com uma segurança especificada (Windows NT somente), e pode ser acessado usando thrdaddr, que é o identificador de segmento.
A rotina em start_address passado para _beginthreadex deve usar __stdcall (para código nativo) ou ( __clrcall para código gerenciado) que chama a convenção e deve retornar um código de saída de segmento.
_beginthreadex retorna 0 em caso de falha, em vez de -1L.
Um segmento criado com _beginthreadex é finalizado com uma chamada a _endthreadex.
A função de _beginthreadex oferece mais controle sobre como o segmento é criado do que faz _beginthread .A função de _endthreadex também é mais flexível.Por exemplo, com _beginthreadex, você pode usar as informações de segurança, defina o estado inicial do segmento suspenso que executa (ou), e obter o identificador do segmento de segmento recém-criado.Você também pode usar a alça de segmento retornada por _beginthreadex por APIs de sincronização, que você não pode fazer com _beginthread.
É mais seguro usar _beginthreadex de _beginthread.Se o segmento gerado por _beginthread sai rapidamente, o identificador retornada para o chamador de _beginthread pode ser válido, ou pior, aponte para outro segmento.No entanto, a alça retornada por _beginthreadex tem que ser fechada pelo chamador de _beginthreadex, o que garante para ser um identificador válido se _beginthreadex não retornou um erro.
Você pode chamar _endthread ou _endthreadex explicitamente para finalizar um segmento; no entanto, _endthread ou o _endthreadex são chamados automaticamente quando o segmento retorna a rotina passado como um parâmetro.Um thread finalizar com uma chamada a endthread ou a _endthreadex ajuda a garantir a recuperação apropriada de recursos alocados para o segmento.
_endthread fechado automaticamente a alça de segmentos (enquanto _endthreadex não faz).Como consequência, ao usar _beginthread e _endthread, não feche explicitamente o identificador de segmentos chamando API do Win32 CloseHandle .Esse comportamento difere ExitThread API do Win32.
Observação |
---|
Para um arquivo executável associado com Libcmt.lib, não chamar a API Win32 ExitThread ; isso impede que o sistema de tempo de execução recuperar recursos alocados._endthread e recuperação de _endthreadex atribuiu recursos de segmento e em seguida ExitThread. |
O sistema operacional trata a alocação de pilha quando _beginthread ou _beginthreadex são chamados; você não precisa passar o endereço da pilha do segmento para qualquer uma dessas funções.Além disso, o argumento de stack_size pode ser 0, nesse caso o sistema operacional usa o mesmo valor que a pilha especificada para o segmento principal.
arglist é um parâmetro para ser passado para o segmento recém-criado.Normalmente é o endereço de um item de dados, como uma cadeia de caracteres.arglist pode ser NULL se ele não for necessário, mas _beginthread e _beginthreadex devem ser fornecidos com qualquer valor à passo para o novo segmento.Todos os segmentos terminam se qualquer segmento chama abort, exit, _exit, ou ExitProcess.
A localidade do novo segmento é herdada do segmento pai.Se o segmento a localidade é ativada por uma chamada a _configthreadlocale (ou global ou para novos segmentos somente), o segmento pode alterar a localidade independente de seu pai chamando setlocale ou _wsetlocale.Para obter mais informações, consulte Localidade.
Para código misturado e puro, _beginthread e _beginthreadex têm duas sobrecargas, uma que usa um ponteiro de função nativo de chamada- convenção, a outra que usa um ponteiro de função de __clrcall .A primeira sobrecarga não é seguro aplicativo domínio e nunca não será.Se você estiver escrevendo código misturando ou puro você deve garantir que o novo segmento entre no domínio de aplicativo correto antes que acessa recursos gerenciados.Você pode fazer isso, por exemplo, usando Função call_in_appdomain.A segunda sobrecarga é seguro aplicativo domínio; o segmento recém-criado sempre terminará anterior no domínio de aplicativo do chamador de _beginthread ou de _beginthreadex.
Requisitos
Rotina |
Cabeçalho necessário |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Para mais informações, consulte Compatibilidade de compatibilidade na introdução.
Bibliotecas
Versões de com Bibliotecas em tempo de execução de C somente.
Para usar _beginthread ou _beginthreadex, o aplicativo deve vincular com uma das bibliotecas em tempo de execução com vários segmentos de C.
Exemplo
O exemplo a seguir usa _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();
}
pressione qualquer chave ao final
O código de exemplo a seguir demonstra como você pode usar a alça de segmento retornada por _beginthreadex com a sincronização API WaitForSingleObject.O segmento principal espera o segundo segmento para terminar antes de continuar.Quando o segundo segmento chama _endthreadex, faz com que seu objeto de segmento vá para o estado signaled.Isso permite que o segmento principal continuar a executar.Isso não pode ser feito com _beginthread e _endthread, porque _endthread chama CloseHandle, destruindo o objeto de segmento antes que possa ser definido para o estado signaled.
// 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 );
}
Equivalência do .NET Framework
System::Threading::Thread::Start