_beginthread, _beginthreadex

Создает поток.

Важное примечаниеВажно

Этот API нельзя использовать в приложениях, запускаемых в среде выполнения Windows.Дополнительные сведения см. в разделе Функции CRT не поддерживаются при /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 
);

Параметры

  • start_address
    Начальный адрес процедуры, начинается выполнение нового потока.Для _beginthread, соглашение о вызовах или __cdecl (для машинного кода) или __clrcall (для управляемого кода); для _beginthreadex это или __stdcall (для машинного кода) или __clrcall (для управляемого кода).

  • stack_size
    Размер стека для нового потока или 0.

  • Arglist
    Список аргументов, которые должны быть переданы новым поток или NULL.

  • Security
    Указатель на структуру SECURITY_ATTRIBUTES определяет, возвращает ли дескриптор может быть унаследован дочерними процессами.NULL, если дескриптор не наследуется.Быть NULL для приложений Windows 95.

  • Initflag
    Начальное состояние нового потока (0 или CREATE_SUSPENDED для запуска для приостановленный); используйте ResumeThread для выполнения потока.

  • Thrdaddr
    Указывает на 32 разрядной переменной, которая получает идентификатор потока.Может иметь значение NULL, в случае которого он не используется.

Возвращаемое значение

В случае успеха каждая из этих функций возвращает дескриптор вновь созданный поток; однако если вновь созданный поток покидает слишком быстро, _beginthread не может возвращать допустимый дескриптор (см. описание в разделе Remarks )._beginthread возвращает -1L при возникновении ошибки в случае, если параметру errno присвоено значение EAGAIN слишком много потоков, значение EINVAL, если аргумент является недопустимым или размер стека неверен, или значение EACCES в случае недостаточных ресурсов (например, память)._beginthreadex возвращает 0 при возникновении ошибки, в которой задается вариант errno и _doserrno.

Если startaddress имеет значение NULL, то обработчик вызывается недопустимого параметра, как описано в разделе Проверка параметров.Если продолжение выполнения разрешено, эти функции устанавливают errno в EINVAL и возвращают -1.

Дополнительные сведения об этих и других кодах возврата см. в разделе _doserrno, errno, _sys_errlist и _sys_nerr.

Дополнительные сведения о uintptr_t см. в разделе Стандартные типы.

Заметки

Функция _beginthread создает поток, начинается выполнение процедуры в start_address.В процедуре start_address должна использовать __cdecl (для машинного кода) или соглашение о вызовах __clrcall (для управляемого кода) и не должна иметь возвращаемого значения.При возврате потока из этой процедуры, он завершается автоматически.Дополнительные сведения о потоках см. в разделе Многопоточность.

_beginthreadex похож на API Win32 CreateThread делает более точно, чем _beginthread._beginthreadex отличается от _beginthread следующими способами.

  • _beginthreadex имеет 3 дополнительных параметров. initflag, security и threadaddr.Новый поток можно создать в приостановленном состоянии, определенной с безопасностью Windows (NT только) и может быть получен с помощью thrdaddr, которая идентификатор потока.

  • В процедуре start_address прошла значение _beginthreadex должна использовать __stdcall (для машинного кода) или соглашение о вызовах __clrcall (для управляемого кода) и должна возвращать код завершения потока.

  • _beginthreadex возвращает 0 при ошибке, а не -1L.

  • Поток, созданный с _beginthreadex завершается вызовом метода _endthreadex.

Функция _beginthreadex обеспечивает большую элемента управления, как поток создается _beginthread не требуется.Функция _endthreadex также является более гибким.Например, с помощью _beginthreadex, сведения о безопасности использования задайте начальное состояние потока (или приостановить выполнение) и получить идентификатор потока, созданного потока.Можно также использовать дескриптор потока, возвращаемого _beginthreadex с API синхронизации, которые невозможно выполнить с _beginthread.

Это безопаснее использовать _beginthreadex, чем _beginthread.Если поток, созданный _beginthread окажутся быстро, дескриптор возвращает вызывающему объекту _beginthread может быть недопустим или, производительность, указывает на другой поток.Однако возвращает дескриптор _beginthreadex должен быть закрыт вызывающим объектом _beginthreadex, поэтому гарантированно является допустимым, если дескриптором _beginthreadex возвращает ошибку.

Можно вызвать _endthread или _endthreadex, чтобы явно завершить поток; однако или _endthread _endthreadex вызываются автоматически при возврате потока из процедуры, переданной в качестве параметра.Завершить поток, вызвав метод endthread или _endthreadex помогает обеспечить правильное восстановление выделенных ресурсов для потока.

_endthread автоматически закрывает дескриптор потока (а не _endthreadex делает).Поэтому при использовании _beginthread и _endthread, явно закрыть дескриптор потока путем вызова API Win32 CloseHandle.Это расширение функциональности отличается от API Win32 ExitThread.

ПримечаниеПримечание

Для исполняемого файла связанного с Libcmt.lib, не следует вызывать API Win32 ExitThread; это предотвращает времени выполнения системы из исправления выбранные ресурсы._endthread и _endthreadex исправления выбранные ресурсы потока и затем вызывает метод ExitThread.

Операционная система обрабатывает выделение стека, если _beginthread или _beginthreadex вызываются; нет необходимости передавать стековый адрес потока в любой из этих функций.Кроме того, аргумент stack_size может быть 0, в случае которого операционная система использует то же значение, что и стека определила для основного потока.

параметр arglist, передаваемые вновь созданный поток.Обычно адрес элемента данных, такие как символьная строка.arglist может иметь значение NULL, если он не является обязательным, но _beginthread и _beginthreadex следует убедиться, что с некоторым значением, переданных в новый поток.Все потоки завершены, если любой поток вызывает метод abort, exit, _exit или ExitProcess.

Языковой стандарт нового потока наследуется от родительского потока.Если в каждом потоке языковой стандарт пользователя при вызове _configthreadlocale (или глобально или только для новых потоков), поток может изменить его языковой стандарт независимо от родительского элемента, вызвав метод setlocale или _wsetlocale.Дополнительные сведения см. в разделе Языковой стандарт.

Для смешанного и чистого кода _beginthread и _beginthreadex имеют 2, одной перегруженной функции, принимающей собственный указатель соглашения о вызовах, другая, принимающую указатель на функцию __clrcall.Первый перегруженный метод не безопасного домена приложения и никогда не будет.Если смешанный записи или, чистого кода необходимо убедиться, что новый поток входит правильный домен приложения, прежде чем обращаться к управляемые ресурсы.Можно сделать это, например, с помощью Функция call_in_appdomain.Вторая перегруженная безопасное домена приложения; вновь созданный поток всегда приведет к в домене приложения вызывающего объекта _beginthread или _beginthreadex.

Требования

Функция

Требуемый заголовок

_beginthread

<process.h>

_beginthreadex

<process.h>

Дополнительные сведения о совместимости см. в разделе Совместимость во введении.

Библиотеки

Многопоточные только версии Библиотеки времени выполнения C.

Чтобы использовать _beginthread или _beginthreadex, его необходимо связать с одной из многопотоковой библиотеки времени выполнения C.

Пример

В следующем примере используются функции _beginthread и _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();
}
  нажмите клавишу любой ключ для выполнения

В следующем примере кода показано, как использовать дескриптор потока, возвращаемый методом _beginthreadex с помощью API WaitForSingleObject синхронизации.Основной поток ожидает завершения другой поток для выполнения до его продолжение.Если другой поток вызывает _endthreadex, он вызывает его объект потока перейти в сигнальное состояние.Это позволяет основной поток, чтобы продолжить работу.Это не может быть выполнено с _beginthread и _endthread, поскольку _endthread вызывает CloseHandle, уничтожение объекта потока, прежде чем его можно задать в сигнальное состояние.

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

Эквивалент в .NET Framework

System::Threading::Thread::Start

См. также

Ссылки

Процесс и управление среды

_endthread, _endthreadex

abort

exit, _exit

GetExitCodeThread