Udostępnij za pośrednictwem


_beginthread, _beginthreadex

Tworzy wątek.

Ważna uwagaWażne

Ten interfejs API nie można używać w aplikacji, których wykonywanie w czasie wykonywania systemu Windows.Aby uzyskać więcej informacji, zobacz CRT funkcje nie obsługiwane przez /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 się wykonywanie nowego wątku.Dla _beginthread, konwencja wywołania jest albo __cdecl (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego); dla _beginthreadex, to albo __stdcall (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego).

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

  • Arglist
    Lista argumentów mają być przekazywane do nowego wątku lub wartość NULL.

  • Security
    Wskaźnik, aby SECURITY_ATTRIBUTES strukturę, która określa, czy zwracany uchwyt mogą być dziedziczone przez procesy podrzędne.Jeśli ma wartość NULL, uchwyt nie może być dziedziczona.Musi to być aplikacje NULL dla systemu Windows 95.

  • Initflag
    Stan nowy wątek początkowy (0 z rzędu lub CREATE_SUSPENDED dla zawieszone); Użyj ResumeThread do wykonania wątku.

  • Thrdaddr
    Wskazuje zmienna 32-bitowe, która odbiera identyfikator wątku.Może być NULL, w którym to przypadku nie jest używany.

Wartość zwracana

W przypadku powodzenia, każda z tych funkcji zwraca uchwyt nowo utworzonego wątku; jednak, jeśli nowo utworzony wątek kończy działanie zbyt szybko _beginthread mogą nie zwracać prawidłowy uchwyt (zobacz Omówienie w Remarks sekcji)._beginthreadZwraca wartość-1 L na błąd, w którym to przypadku errno jest ustawiona na EAGAIN Jeśli istnieje zbyt wiele wątków, do EINVAL Jeśli argument jest nieprawidłowy lub rozmiar stosu jest niepoprawny lub do EACCES w przypadku niewystarczających zasobów (takich jak pamięć)._beginthreadexZwraca wartość 0 w błąd, w którym to przypadku errno i _doserrno są ustawione.

Jeśli startaddress jest NULL, program obsługi nieprawidłowy parametr jest wywoływana, zgodnie z opisem w Sprawdzanie poprawności parametru.Jeśli wykonanie może kontynuować, ustaw te funkcje errno do EINVAL i zwraca –1.

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

Aby uzyskać więcej informacji o uintptr_t, zobacz Standardowe typy.

Uwagi

_beginthread Funkcja tworzy wątek, który rozpoczyna się wykonywanie rutynowych w start_address.Rutynowe w start_address należy użyć __cdecl (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego) konwencji wywoływania i powinien mieć nie zwraca żadnej wartości.Gdy wątek, zwraca się w tym rutynowe, jego zakończeniem automatycznie.Aby uzyskać więcej informacji na temat wątków, zobacz wielowątkowość.

_beginthreadexpodobne do Win32 CreateThread API więcej niż ściśle _beginthread czy._beginthreadexróżni się od _beginthread w następujący sposób:

  • _beginthreadexma trzy dodatkowe parametry: initflag, security, i threadaddr.Nowy wątek mogą być tworzone w stanie wstrzymania, z określonym zabezpieczeń (tylko system Windows NT) i są dostępne przy użyciu thrdaddr, który jest identyfikator wątku.

  • Rutynowe w start_address przekazany do _beginthreadex należy użyć __stdcall (dla kodu macierzystego) lub __clrcall (dla kodu zarządzanego) konwencji wywoływania i musi zwrócić kod wyjścia wątku.

  • _beginthreadexZwraca 0 w przypadku awarii, a nie-1 L.

  • Wątek utworzony za pomocą _beginthreadex zostaje zakończona poprzez wywołanie _endthreadex.

_beginthreadex Funkcja daje większą kontrolę nad procesem tworzenia wątku niż _beginthread czy._endthreadex Funkcja jest również bardziej elastyczne.Na przykład z _beginthreadex, można użyć informacji o zabezpieczeniach, ustawić stan początkowy wątku (uruchomiona lub zawieszone) i uzyskać identyfikator wątku nowo utworzonego wątku.Również są w stanie za pomocą uchwytu wątku, zwracane przez _beginthreadex z synchronizacją interfejsów API, którego nie można zrobić z _beginthread.

To bezpieczniej jest używać _beginthreadex niż _beginthread.Jeśli wątek generowane przez _beginthread zamyka się szybko, zwracany uchwyt do obiektu wywołującego z _beginthread może być nieprawidłowy lub, gorzej, wskaż inny wątek.Jednakże uchwyt zwrócony przez _beginthreadex musi być zamknięty przez obiekt wywołujący _beginthreadex, więc to zapewniona jest prawidłowym dojściem, jeśli _beginthreadex nie zwróciła błąd.

Można wywołać _endthread lub _endthreadex jawnie, aby zakończyć wątek; Jednakże _endthread lub _endthreadex jest wywoływana automatycznie, gdy wątek wraca ze rutynowych przekazane jako parametr.Kończącym wątek o wywołaniu endthread lub _endthreadex pozwala uzyskać pewność poprawnego odzyskania środków przydzielonych uczestnikom o wątku.

_endthreadautomatycznie zamyka uchwytu wątku (podczas gdy _endthreadex nie).W związku z tym korzystając z _beginthread i _endthread, nie zamykaj jawnie uchwyt do wątku poprzez wywołanie Win32 CloseHandle interfejsu API.To zachowanie różni się od Win32 ExitThread interfejsu API.

[!UWAGA]

Dla pliku wykonywalnego, związane z Libcmt.lib, nie wywoła Win32 ExitThread interfejsu API. Zapobiega to odzyskanie przydzielone zasoby systemu w czasie wykonywania._endthreadi _endthreadex odzyskiwania zasobów przydzielonych wątku, a następnie wywołać ExitThread.

System operacyjny obsługuje alokacji stosu po albo _beginthread lub _beginthreadex nazywa się; nie trzeba przekazywać adres stosu wątku do jednej z tych funkcji.Dodatkowo stack_size argument może mieć wartość 0, w którym przypadku system operacyjny używa tej samej wartości jak stos określony dla głównego wątku.

arglistjest parametrem mają być przekazywane do nowo utworzonego wątku.Zazwyczaj jest to adres elementu danych, takie jak ciąg znaków.arglistmoże być NULL Jeśli nie jest potrzebna, ale _beginthread i _beginthreadex musi posiadać pewną wartość, aby przejść do nowego wątku.Wszystkie wątki są przerywane, jeżeli dowolnego wątku wywołania abort, exit, _exit, lub ExitProcess.

Ustawienia regionalne nowy wątek jest dziedziczona z jego wątek nadrzędny.Jeśli na wątek ustawień regionalnych jest włączony przez wywołanie do _configthreadlocale (albo globalnie, albo dla nowych wątków tylko), wątek można zmienić jego ustawienia regionalne niezależnie ze swojej witryny nadrzędnej, wywołując setlocale lub _wsetlocale.Aby uzyskać więcej informacji, zobacz ustawień regionalnych.

Mieszane i czysty kod _beginthread i _beginthreadex mają dwa przeciążeń, z nich przy wskaźnik macierzystych funkcji telefonicznej Konwencji, inne biorąc __clrcall wskaźnika funkcji.Pierwszy przeciążenie nie jest bezpieczny domeny aplikacji i nigdy nie będzie się.Jeśli pisze się kod czystych lub mieszanych należy się upewnić, że nowy wątek wchodzi domeny prawidłowe stosowanie przed nią zarządzanych zasobów.Możesz można to zrobić, na przykład za pomocą Funkcja call_in_appdomain.Drugi przeciążenie jest aplikacją bezpieczne domeny; nowo utworzony wątek zawsze kończy się w domenie aplikacji wywołującego _beginthread lub _beginthreadex.

Wymagania

Rozpoczęto wykonywanie procedury

Wymaganego nagłówka

_beginthread

<process.h>

_beginthreadex

<process.h>

Informacji dotyczących zgodności, zobacz zgodności we wprowadzeniu.

Biblioteki

Wielowątkowe wersjach biblioteki uruchomieniowej C tylko.

Aby użyć _beginthread lub _beginthreadex, aplikacji, należy połączyć z jednym z wielowątkowe biblioteki uruchomieniowej C.

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 *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();
}
  Naciśnij dowolny klawisz, aby zakończyć

Następujący przykładowy kod demonstruje, korzystania z uchwyt wątku, zwracane przez _beginthreadex z synchronizacją API WaitForSingleObject.Główny wątek czeka na zakończenie przed kontynuowaniem drugiego wątku.Kiedy drugi wątek wywoła _endthreadex, powoduje jego obiektu wątku przejść w stan zasygnalizowany.Dzięki temu wątkowi głównemu nadal działać.Nie jest to możliwe z _beginthread i _endthread, bo _endthread wywołania CloseHandle, zniszczenie obiektu wątku, zanim można ją ustawić stan zasygnalizowany.

// 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

Proces i kontroli środowiska

_endthread, _endthreadex

abort

exit, _exit

GetExitCodeThread