_beginthread
, _beginthreadex
Создает поток.
Синтаксис
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
структуру, которая определяет, может ли возвращаемый дескриптор наследоваться дочерними процессами. Если Security
есть NULL
, дескриптор не может быть унаследован.
initflag
Флаги, управляющие начальным состоянием нового потока. Установите initflag
значение 0 для немедленного выполнения или CREATE_SUSPENDED
создания потока в приостановленном состоянии; используется ResumeThread
для выполнения потока. STACK_SIZE_PARAM_IS_A_RESERVATION
Установите initflag
для флага, который будет использоваться stack_size
в качестве начального резервного размера стека в байтах; если этот флаг не указан, stack_size
указывает размер фиксации.
thrdaddr
Указывает на 32-разрядную переменную, которая получает идентификатор потока. Если это NULL
так, он не используется.
Возвращаемое значение
В случае успеха каждая из этих функций возвращает дескриптор во вновь созданный поток; однако если вновь созданный поток выполняет выход слишком быстро, _beginthread
может не возвращать допустимый дескриптор. (См. обсуждение в разделе "Примечания".) При ошибке _beginthread
возвращает значение -1L и errno
имеет EAGAIN
значение, если имеется слишком много потоков, в EINVAL
том случае, если аргумент недопустим или размер стека неверный, или EACCES
если недостаточно ресурсов (например, памяти). При возникновении ошибки _beginthreadex
возвращает 0, а errno
и _doserrno
заданы.
В противном start_address
NULL
случае вызывается недопустимый обработчик параметров, как описано в разделе "Проверка параметров". Если продолжение выполнения разрешено, эти функции устанавливают для errno
значение EINVAL
и возвращают -1.
Дополнительные сведения об этих и других кодах возврата см. в разделе errno
, _doserrno
и _sys_nerr
_sys_errlist
.
Дополнительные сведения см. в uintptr_t
разделе "Стандартные типы".
Замечания
Функция _beginthread
создает поток, который начинает выполнение процедуры в start_address
. В процедуре start_address
необходимо использовать __cdecl
(для машинного кода) или соглашение о вызовах __clrcall
(для управляемого кода); там не должно быть возвращаемого значения. Когда поток возвращается из этой подпрограммы, он завершается автоматически. Дополнительные сведения о потоках см. в статье о поддержке многопоточных операций для старого кода (Visual C++).
_beginthreadex
напоминает API Win32 CreateThread
более тесно, чем _beginthread
это делает. _beginthreadex
имеет следующие отличия от _beginthread
:
_beginthreadex
имеет три дополнительных параметра:initflag
,Security
иthreadaddr
. Новый поток можно создать в приостановленном состоянии (с заданной безопасностью), а доступ к нему можно осуществлять с помощью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
явно завершать поток. Однако или _endthreadex
вызывается автоматически, когда поток возвращается из подпрограммы, _endthread
передаваемой в качестве параметра. Остановка потока вызовом метода _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
. Потоки, у которых нет набора флагов языкового стандарта для каждого потока, могут повлиять на сведения о языковом стандарте во всех остальных потоках, которые также не имеют набора флагов языкового стандарта для каждого потока, а также все созданные потоки. Дополнительные сведения см. в разделе Locale.
Для /clr
кода _beginthread
_beginthreadex
и каждая из них имеет две перегрузки. Один принимает собственный указатель функции-соглашения, а другой принимает __clrcall
указатель функции. Первая перегрузка не является безопасной для домена приложения и никогда не будет. Если вы пишете /clr
код, перед доступом к управляемым ресурсам необходимо убедиться, что новый поток вводит правильный домен приложения. Это можно сделать, например, с помощью call_in_appdomain
. Вторая перегрузка является доменобезопасной; только что созданный поток всегда завершается в домене приложения вызывающего объекта _beginthread
или _beginthreadex
.
По умолчанию глобальное состояние этой функции ограничивается приложением. Чтобы изменить это поведение, см . статью "Глобальное состояние" в CRT.
Требования
Маршрут | Обязательный заголовок |
---|---|
_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 * );
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 = ¶m;
// 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 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, ®ion);
// 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();
}
Чтобы закрыть приложение-пример, нажмите любую клавишу.
В следующем примере кода показано, как использовать дескриптор потока, возвращаемый _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 );
}
Creating second thread...
In second thread...
Counter should be 1000000; it is-> 1000000