Compartilhar via


_beginthread, _beginthreadex

Cria um thread.

Importante

Não é possível usar essa API em aplicativos que são executados em Tempo de Execução do Windows ou compilados com uso do comutador clr:pure.Para obter mais informações, consulte Funções de CRT sem suporte 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 inicial de uma rotina que inicia a execução de um novo thread. Para _beginthread, a convenção de chamada é __cdecl (para códigos nativos) ou __clrcall (para códigos gerenciados). Para, _beginthreadex, a convenção é __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
    Ponteiro para uma estrutura SECURITY_ATTRIBUTES que determina se o indicador retornado pode ser herdado por processos filhos. Se Security for NULL, o indicador não poderá ser herdado. Esse valor deve ser NULL para aplicativos Windows 95.

  • 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 com o sinalizador STACK_SIZE_PARAM_IS_A_RESERVATION para usar stack_size como 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 o valor for NULL, esse parâmetro não é usado.

Valor de retorno

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 sessão Observações. Em caso de erro, _beginthread retorna -1L e errno é definido como EAGAIN se houver muitos threads para EINVAL se o argumento for inválido ou o tamanho da pilha estiver incorreto, ou para 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 startaddress for NULL, o indicador de parâmetro inválido é invocado, como descrito em Validação do 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, consulte errno, _doserrno, _sys_errlist e _sys_nerr.

Para obter mais informações sobre uintptr_t, 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 é terminado automaticamente. Para obter mais informações sobre threads, consulte Suporte multithread para código anterior (Visual C++).

_beginthreadex parece mais com a API CreateThread do Win32 do que o _beginthread. _beginthreadex é diferente de _beginthread nestes aspectos:

  • _beginthreadex tem três parâmetros adicionais: initflag, security e threadaddr. O novo thread pode ser criado em estado suspenso, com a segurança especificada, e pode ser acessado com uso de thrdaddr, 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 criado com uso de _beginthreadex é terminado pela chamada a _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 é possível com a função _beginthread.

É mais seguro usar _beginthreadex 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 indicador retornado por _beginthreadex deve ser encerrado pelo chamador de _beginthreadex, para que ele seja 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 informada como parâmetro à função. Chamar a função _endthread ou _endthreadex para terminar um thread ajuda a garantir que os recursos alocados ao thread sejam devidamente recuperados.

A função _endthread fecha o identificador de thread automaticamente. Já a função _endthreadex não faz isso. Portanto, ao usar as funções _beginthread e _endthread, não feche o identificador de thread explicitamente chamando a API CloseHandle do Win32. O comportamento da API ExitThread do Win32 é diferente.

Dica

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. Geralmente, trata-se do endereço de um item de dados, como uma cadeia de caracteres. arglist pode ser NULL se esse valor não for necessário, mas _beginthread e _beginthreadex devem ter outros valores para apresentar ao novo thread. Todos os threads são terminados se o thread chamar abort, exit, _exit ou ExitProcess.

A localidade do novo thread é herdada do thread pai. Se a chamada a _configthreadlocale habilitar a localidade por thread (globalmente ou somente para novos threads), o thread pode alterar sua localidade, independente do pai, com a chamada a setlocale ou _wsetlocale. Para obter mais informações, consulte Localidade.

Para obter códigos combinados e puros, _beginthread e _beginthreadex têm duas sobrecargas. Uma delas usa um ponteiro de funções de convenção de chamadas nativo. A outra usa um ponteiro da função __clrcall. A primeira sobrecarga não é à prova de domínio do aplicativo e nunca será. Se estiver gravando códigos combinados ou puros, você deve garantir que o novo thread insira o domínio de aplicativo certo antes de acessar os recursos gerenciados. Você pode fazer isso, por exemplo, usando Função 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.

Requisitos

Rotina

Cabeçalho necessário

_beginthread

<process.h>

_beginthreadex

<process.h>

Para obter mais informações de compatibilidade, consulte Compatibilidade.

Libraries

Somente versões multithreaded da biblioteca de tempo de execução C.

Para usar _beginthread ou _beginthreadex, o aplicativo deve vincular-se a uma das bibliotecas de tempo de execução C multithreaded.

Exemplo

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 = &param;

    // 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 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, &region);

        // 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, o objeto do thread entra no estado sinalizado. Isso permite que o thread principal continue em execução. Não é possível fazer isso com _beginthread e _endthread porque _endthread chama CloseHandle, que destrói o objeto do thread antes que ele seja definido no 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 );
}
          

Equivalência do .NET Framework

System::Threading::Thread::Start

Consulte também

Referência

Processo e controle de ambiente

_endthread, _endthreadex

abort

exit, _exit

GetExitCodeThread