_beginthread, _beginthreadex
Vytvoří vlákno.
Důležité |
---|
Toto rozhraní API nelze použít v aplikacích, které jsou spuštěny v prostředí Windows Runtime nebo jsou zkompilovány pomocí clr:pure přepnout.Další informace naleznete v tématu CRT funkce nepodporované s /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
Počáteční adresa rutiny, která zahájí provádění nového vlákna.Pro _beginthread, konvence volání je buď __cdecl (pro nativní kód) nebo __clrcall (pro spravovaný kód). pro _beginthreadex, je buď __stdcall (pro nativní kód) nebo __clrcall (pro spravovaný kód).stack_size
Velikost zásobníku pro nové vlákno nebo 0.arglist
Seznam argumentů, která bude předána do nového vlákna, nebo hodnota NULL.Security
Ukazatel na SECURITY_ATTRIBUTES strukturu, která určuje, zda může být vrácená popisovač zděděna podřízené procesy.Pokud Security má hodnotu NULL, nemůže být odvozeny popisovač.Musí být NULL pro systém Windows 95 aplikací.initflag
Příznaky, které řídí počáteční stav nového vlákna.Nastavit initflag k 0 spustit okamžitě, nebo na CREATE_SUSPENDED Chcete-li vytvořit vlákno v pozastaveném stavu; použít ResumeThread toto vlákno spustit.Nastavit initflag k STACK_SIZE_PARAM_IS_A_RESERVATION příznak, který pomocí stack_size jako počáteční rezervy velikosti zásobníku v bajtů. Pokud tento příznak není zadán, stack_size Určuje velikost potvrzení.thrdaddr
Body 32bitové proměnné, která obdrží identifikátor vlákna.Pokud je hodnota NULL, není použit.
Vrácená hodnota
V případě úspěšného ověření každá z těchto funkcí vrátí popisovač ke nově vytvořený podprocesu. Nicméně, je-li nově vytvořený vlákno ukončí příliš rychle _beginthread nemusí vrátit platný popisovač.(Viz popis v oddílu Poznámky.) Na chybu _beginthread vrátí L-1, a errno je nastavena na EAGAIN dojde-li příliš mnoho vlákna, do EINVAL -li argument je neplatný nebo velikost zásobníku je nesprávné, nebo o EACCES -li k dispozici také dostatek prostředků (např. paměti).Na chybu _beginthreadex , vrátí hodnotu 0, a errno a _doserrno jsou nastaveny.
Pokud startaddress má hodnotu NULL, je volána obslužná rutina neplatný parametr, jak je popsáno v Ověření parametru.Pokud je povoleno spuštění chcete-li pokračovat, tyto funkce nastavit errno k EINVAL a vrátí hodnotu -1.
Další informace o těchto a dalších návratové kódy naleznete v tématu errno, _doserrno, _sys_errlist, and _sys_nerr.
Další informace o objektu uintptr_t získáte v tématu Standardní typy.
Poznámky
_beginthread Funkce vytvoří vlákna, které začíná spuštění rutiny na adrese start_address.Rutina na adrese start_address musí používat __cdecl (pro nativní kód) nebo __clrcall (pro spravovaný kód) konvence volání a by měl nemají návratovou hodnotu.Po návratu vlákno z této rutiny bude automaticky ukončena.Další informace o vláken naleznete v tématu Podpora více vláken ve starším kódu (Visual C++).
_beginthreadexrozhraní Win32 se podobá CreateThread rozhraní API další těsně než _beginthread nemá._beginthreadexse liší od _beginthread z následujících způsobů:
_beginthreadexmá tři další parametry: initflag, security, a threadaddr.Nové vlákno lze vytvořit v pozastaveném stavu, zadaný zabezpečení a je přístupný pomocí thrdaddr, což je identifikátor vlákna.
Rutina na adrese start_address který je předán _beginthreadex musí používat __stdcall (pro nativní kód) nebo __clrcall (pro spravovaný kód) konvence volání a musí vracet ukončovací kód vlákna.
_beginthreadexselhání, nikoli L-1, vrátí hodnotu 0.
Vlákna, které je vytvořen pomocí _beginthreadex je ukončeno voláním _endthreadex.
_beginthreadex Funkce vám dává větší kontrolu nad vytvářením vlákna než _beginthread nepodporuje._endthreadex Funkce je také více flexibilní.Můžete například s _beginthreadex, můžete použít informace o zabezpečení, nastavení počátečního stavu vlákna (spuštěna nebo pozastavena) a získejte identifikátor vlákna nově vytvořený vlákna.Můžete také použít popisovač podprocesu, který je vrácen _beginthreadex se synchronizací rozhraní API, což není možné provádět pomocí _beginthread.
Je bezpečnější používat _beginthreadex než _beginthread.Pokud vlákna, které je generováno _beginthread rychle a ukončí popisovač, který je vrácen do volajícího _beginthread může být neplatná nebo přejděte na příkaz jiného vlákna.Však popisovač, který je vrácen _beginthreadex musí být ukončená volající _beginthreadex, takže je zaručena na platný popisovač Pokud _beginthreadex nevrátil k chybě.
Můžete volat _endthread nebo _endthreadex explicitně na ukončení podprocesu. však _endthread nebo _endthreadex je zavolána automaticky při vlákno vrátí z rutina, která je předána jako parametr.Ukončení vlákna s voláním funkce _endthread nebo _endthreadex pomáhá zajistit správnou obnovení materiálů, které jsou přiděleny pro vlákno.
_endthreadautomaticky zavře popisovač podprocesu, že _endthreadex nepodporuje.Proto při použití _beginthread a _endthread, popisovač podprocesu explicitně nezavírejte voláním rozhraní Win32 funkce CloseHandle rozhraní API.Toto chování se liší od rozhraní Win32 ExitThread rozhraní API.
[!POZNÁMKA]
Pro spustitelný soubor propojena s Libcmt.lib, nevolejte Win32 ExitThread rozhraní API tak, aby si běhu systému zabránit recyklovat přidělených prostředků._endthreada _endthreadex uvolnit prostředky přidělené vlákna a poté zavolá ExitThread.
Operační systém zpracovává přidělení zásobníku při buď _beginthread nebo _beginthreadex je volána; Nemáte k předání adresu zásobníku vlákno do některé z těchto funkcí.Kromě toho stack_size argument může být 0, ve kterém případu operační systém používá stejnou hodnotu jako zásobníku, která je určena pro hlavní vlákno.
arglistje parametr mají být předány do nově vytvořeného vlákna.Obvykle je to adresa položky dat, jako je například řetězec znaků.arglistmůže mít hodnotu NULL, pokud není nutné jej, ale _beginthread a _beginthreadex musí být zadána některá z hodnot mají být předána do nového vlákna.Všechna vlákna budou ukončeny, pokud žádné vlákno volání abort, exit, _exit, nebo ExitProcess.
Národní prostředí nové vlákno se dědí z jeho nadřazený vlákno.Pokud je povoleno národní prostředí pro vlákno voláním _configthreadlocale (globálně nebo pro nového vlákna), vlákno lze změnit pouze jeho národní prostředí samostatně od svého nadřazeného voláním setlocale nebo _wsetlocale.Další informace naleznete v tématu Národní prostředí.
Pro smíšené a čisté kód _beginthread a _beginthreadex každý má dvě přetížení – jednu přebírá ukazatel nativní konvence volání funkce, jiné přijímá __clrcall ukazatel funkce.První přetížení není bezpečné pro doménu aplikace a nikdy nebude možné.Pokud píšete smíšená nebo čistého kódu je třeba zkontrolovat, nové vlákno před přistupuje k spravované prostředky vstupuje do správné aplikační domény.Můžete tuto operaci provést, například pomocí call_in_appdomain – funkce.Druhý přetížení je aplikace domény zajišťující bezpečnost; nově vytvořená vlákno vždy skončí v doméně aplikace volajícího _beginthread nebo _beginthreadex.
Požadavky
Rutina |
Požadovaný hlavičkový soubor |
---|---|
_beginthread |
< process.h > |
_beginthreadex |
< process.h > |
Další informace o kompatibilitě naleznete v tématu Kompatibilita.
Knihovny
Ve více vláknech verzích knihoven C run-time pouze.
Chcete-li použít _beginthread nebo _beginthreadex, aplikace se musí propojit s jedním z ve více vláknech knihoven C run-time.
Příklad
V následujícím příkladu _beginthread a _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 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();
}
Stisknutím libovolné klávesy na konec vzorové aplikace.
Následující ukázkový kód ukazuje použití popisovač podprocesu, který je vrácen _beginthreadex se synchronizací rozhraní API WaitForSingleObject.Hlavní vlákno počká na druhé vlákno ukončit před pokračováním.Když volá druhé vlákno _endthreadex, způsobí, že jeho objekt vlákna, přejděte na signalizovaném stavu.To umožňuje primární vlákno pokračovat v práci.Tuto změnu nelze provést s _beginthread a _endthread, protože _endthread volání CloseHandle, které odstraní objekt vlákna předtím, než lze nastavit signalizovaném stavu.
// 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 );
}
Ekvivalent v rozhraní .NET Framework
System::Threading::Thread::Start