Udostępnij za pośrednictwem


_beginthread, _beginthreadex

Tworzy wątku.

Ważna uwagaWażne

Ten interfejs API nie można używać w aplikacji, które są wykonywane w Środowisko wykonawcze systemu Windows lub są tworzone przy użyciu clr:pure przełącznika.Aby uzyskać więcej informacji, zobacz funkcji CRT nie obsługują /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  );

Parametry

  • start_address
    Uruchom adresu procedury, która rozpoczyna wykonanie nowego wątku.Dla _beginthread, jest konwencja wywołania __cdecl (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego); dla _beginthreadex, jest ona __stdcall (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego).

  • stack_size
    Rozmiar stosu dla nowego wątku lub 0.

  • arglist
    Lista argumentów do przekazania do nowego wątku lub wartość NULL.

  • Security
    Wskaźnik do SECURITY_ATTRIBUTES strukturę, która określa, czy zwrócone uchwyt może być dziedziczony przez procesy podrzędne.Jeśli Security ma wartość NULL, nie może być dziedziczona dojście.Musi to być wartość NULL dla systemu Windows 95 aplikacje.

  • initflag
    Flagi kontrolujące początkowy stan nowego wątku.Ustaw initflag do 0 do uruchamiania bezpośrednio, albo na CREATE_SUSPENDED utworzyć wątku w stanie wstrzymania; Użyj ResumeThread do wykonania wątku.Ustaw initflag do STACK_SIZE_PARAM_IS_A_RESERVATION Oznacz flagą, aby użyć stack_size jako rozmiar początkowego rezerwy stosu w bajtach; Jeśli nie określono tej flagi, stack_size Określa rozmiar zatwierdzania.

  • thrdaddr
    Punkty do zmiennej 32-bitowy, który odbiera identyfikator wątku.Jeśli ma wartość NULL, nie jest używany.

Wartość zwracana

W przypadku powodzenia każda z tych funkcji zwraca uchwyt do wątku nowo utworzony; jednak, czy nowo utworzony wątku istnieje zbyt szybko _beginthread nie może zwrócić nieprawidłowy uchwyt.(Zobacz dyskusji w sekcji uwag). W przypadku błędu _beginthread zwraca wartość-1 L, i errno ma ustawioną wartość EAGAIN w przypadku zbyt dużej liczby wątków do EINVAL argument jest nieprawidłowy lub rozmiar stosu jest niepoprawny, czy do EACCES Jeśli za mało zasobów (np. pamięci).W przypadku błędu _beginthreadex zwraca wartość 0, a errno i _doserrno zostały zdefiniowane.

Jeśli startaddress ma wartość NULL, program obsługi nieprawidłowy parametr zostanie wywołany, zgodnie z opisem w Sprawdzanie poprawności parametru.Jeśli jest dozwolone wykonywanie aby kontynuować, ustaw tych funkcji errno do EINVAL i zwraca wartość -1.

Aby uzyskać więcej informacji na temat tych i innych kody powrotne, zobacz errno, _doserrno, _sys_errlist, and _sys_nerr.

Aby dowiedzieć się więcej o obiekcie uintptr_t, zobacz Standardowe typy.

Uwagi

_beginthread Funkcji tworzy wątku, który rozpoczyna wykonanie procedury w start_address.Procedury w start_address muszą mieć __cdecl (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego) konwencji wywoływania i powinna nie zwracanej wartości.Wartość zwrócona przez wątek z tej procedury kończy się automatycznie.Aby uzyskać więcej informacji na temat wątków, zobacz Obsługa wielowątkowości w przypadku starszego kodu (Visual C++).

_beginthreadexpodobny Win32 funkcji CreateThread interfejsu API więcej ściśle niż _beginthread jest._beginthreadexróżni się od _beginthread w następujący sposób:

  • _beginthreadexzawiera trzy dodatkowe parametry: initflag, security, i threadaddr.Nowy wątek można utworzyć w stanie wstrzymania, z określonym zabezpieczeń i można uzyskać przy użyciu thrdaddr, który jest identyfikator wątku.

  • Procedury w start_address przekazania do _beginthreadex należy użyć __stdcall (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego) konwencji wywoływania i musi zwracać kod zakończenia wątku.

  • _beginthreadexZwraca wartość 0 dla błędów, a nie wartość-1 L.

  • Wątek, który jest tworzony przy użyciu _beginthreadex zostaje zakończone przez wywołanie _endthreadex.

_beginthreadex Funkcji zapewnia większą kontrolę nad procesem tworzenia wątku niż _beginthread jest._endthreadex Funkcja jest również bardziej elastyczne.Na przykład z _beginthreadex, użyj informacje o zabezpieczeniach, ustawić stan początkowy wątku (uruchomiony lub zawieszone) i Pobierz identyfikator wątku nowo utworzony wątku.Możesz także użyć dojście wątku, który jest zwracany przez _beginthreadex z synchronizacją interfejsów API, które nie _beginthread.

Jest bezpieczniejsze w użyciu _beginthreadex niż _beginthread.Jeśli wątek, który jest generowany przez _beginthread zamyka szybko, zwracany do wywołującego dojście _beginthread może być nieprawidłowy lub wskaż inny wątek.Jednak dojść, który jest zwracany przez _beginthreadex ma zostać zamknięty przez element wywołujący _beginthreadex, co jest gwarantowana mieć nieprawidłowy uchwyt, jeśli _beginthreadex nie zwrócił błąd.

Można wywołać metodę _endthread lub _endthreadex jawnie na zakończenie wątku; jednak _endthread lub _endthreadex automatycznie jest wywoływane, gdy wątek zwraca z procedury, która została przekazana jako parametr.Przerywanie wątku w wyniku wywołania _endthread lub _endthreadex gwarantuje poprawne odzyskiwania zasobów, które są przydzielone wątku.

_endthreadautomatycznie zamyka dojście wątku, natomiast _endthreadex nie obsługuje.W związku z tym, używając _beginthread i _endthread, nie należy jawnie zamykać dojście wątku przez wywołanie Win32 funkcji CloseHandle interfejsu API.To zachowanie różni się od Win32 ExitThread interfejsu API.

[!UWAGA]

Dla pliku wykonywalnego połączona z Libcmt.lib nie należy wywoływać metody Win32 ExitThread interfejsu API, aby nie uniemożliwiają odzyskiwanie przez system wykonywania przydzielone zasoby._endthreadi _endthreadex odzyskać zasoby przydzielone wątku, a następnie wywołać ExitThread.

System operacyjny obsługuje alokacji stosu podczas albo _beginthread lub _beginthreadex jest wywoływana; nie trzeba przekazać adres stosu wątku do jednej z tych funkcji.Ponadto stack_size argument może być 0, w których przypadku system operacyjny używa tę samą wartość co na stosie, który jest określony dla głównym wątku.

arglistto parametr do przekazania do nowo utworzonego wątku.Zazwyczaj jest to adres elementu danych, takich jak ciąg znaków.arglistmoże mieć wartość NULL, jeśli nie jest wymagana, ale _beginthread i _beginthreadex muszą mieć niektóre wartości do przekazania do nowego wątku.Wszystkie wątki są zakończone, jeśli żadnego wątku wywołania abort, exit, _exit, lub ExitProcess.

Ustawienia regionalne nowego wątku są dziedziczone z nadrzędnego wątku.Jeśli ustawień regionalnych na wątek jest włączone przez wywołanie _configthreadlocale (globalnie lub dla nowo tylko), Wątek można zmienić jej ustawienia regionalne niezależnie z nadrzędnej przez wywołanie metody setlocale lub _wsetlocale.Aby uzyskać więcej informacji, zobacz Regionalne.

Kod, mieszane i czystego _beginthread i _beginthreadex mieć dwie przeciążenia — ma jeden wskaźnik macierzysty konwencja wywołania funkcji, inne ma __clrcall wskaźnik funkcji.Pierwszy przeciążenia nie jest bezpieczne domeny i aplikacji nigdy nie będzie można.Podczas pisania kodu mieszanych lub czystego należy się upewnić, że nowy wątek przechodzi domeny poprawne aplikacji przed uzyskuje dostęp do zasobów zarządzanych.Można to zrobić, na przykład za pomocą call_in_appdomain — Funkcja.Drugi przeciążenia to aplikacja bezpieczne domeny; nowo utworzony wątku zawsze będzie kończyć w domenie aplikacji obiektu wywołującego z _beginthread lub _beginthreadex.

Wymagania

Procedura

Wymagany nagłówek

_beginthread

< process.h >

_beginthreadex

< process.h >

Aby uzyskać więcej informacji na temat zgodności, zobacz Zgodność.

Biblioteki

Wersje wielowątkowe C biblioteki czasu wykonywania tylko.

Aby użyć _beginthread lub _beginthreadex, aplikacji należy połączyć z jednym z wielowątkowe bibliotek C w czasie wykonywania.

Przykład

W poniższym przykładzie użyto _beginthread i _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();
}

Naciśnij dowolny klawisz, aby zakończyć działanie aplikacji przykładu.

Następujący kod pokazuje, jak używać dojście wątku, który jest zwracany przez _beginthreadex z synchronizacją interfejsu API WaitForSingleObject.Główny wątek oczekuje na drugi wątek zakończyć przed kontynuowaniem.Kiedy drugi wątek wywołuje _endthreadex, ta powoduje, że jego obiekt wątku przejść do stanie sygnalizacji.Dzięki temu podstawowy wątku dalsze działanie.Nie można tego dokonać z _beginthread i _endthread, ponieważ _endthread wywołania CloseHandle, który zniszczy obiektu wątku przed może należeć do stanie sygnalizacji.

// 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 );
}
        

Odpowiednik w programie .NET Framework

System::Threading::Thread::Start

Zobacz też

Informacje

Procedury kontroli środowiska

_endthread, _endthreadex

przerwij

exit, _exit

Funkcja GetExitCodeThread