Partilhar via


_beginthread, beginthreadex

Cria um segmento.

Observação importanteImportante

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 NULL

  • Security
    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çãoObservaçã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

Consulte também

Referência

Processo e controle do ambiente

_endthread, _endthreadex

sair, _exit

GetExitCodeThread

anulação