Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Создает поток.
Синтаксис
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